home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…eptember: Technology Seed / September 98 ADC Seed CD.toast / FireWire 1.1 DR2 SDK / Source / FWiX / FWiXApp / FWiXmain.c < prev    next >
Encoding:
Text File  |  1998-01-15  |  90.0 KB  |  3,652 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXMain.c
  3.  
  4.     Contains:    Application software to transfer files over FireWire.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.     
  10.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (jkl)    Jay Lloyd
  23.  
  24.     Change History (most recent first):
  25.  
  26.       <FW32>     6/19/97    jkl        Added support for GetNodeList and SendItems AppleScript
  27.                                     commands. Saved the icons view as a preference. Updated the open
  28.                                     sharing setup command for Tempo to open File Sharing .
  29.       <FW31>     6/10/97    jkl        Made sure a device added message does not result in the same
  30.                                     device getting added twice.
  31.       <FW30>     5/28/97    jkl        Made sure send or receive error is cleared before calling error
  32.                                     dialog. The not cleared error could cause the dialog to
  33.                                     repeatedly display itself.
  34.       <FW29>     5/27/97    jkl        Changed memory allocation for data buffers to ensure they are on
  35.                                     4k boundaries.
  36.       <FW28>     5/16/97    jkl        Corrected some GetPort SetPort bracketing around updates and
  37.                                     drawing.
  38.       <FW27>     5/15/97    jkl        Modified error handling routines to recover from errors during
  39.                                     the transfer check before file sending has started. Held all of
  40.                                     the completion routines.
  41.       <FW26>      5/7/97    jkl        Modified linked lists to double linked lists to simplify
  42.                                     insertion and deletion of list items.
  43.       <FW25>     4/29/97    jkl        Fixed main symbol export. Made sure drop folder exsists before
  44.                                     calling open drop folder routine.
  45.       <FW24>     4/29/97    jkl        Added global alert routine to handle alert event filters.
  46.                                     Corrected a problem that could leave the connected fwix machine
  47.                                     list corrupted.
  48.       <FW23>      4/8/97    jkl        Added page up/down, home, and end key scrolling support. Changed
  49.                                     my BBS initials to not conflict with Jim Luther's.
  50.       <FW22>     3/18/97    jkl        Added new icons. Changed text drawing to use TETextBox. Moved
  51.                                     prefs related routines to prefs.c.
  52.       <FW21>     2/27/97    jkl        Modified preferences to be under receiver control and removed
  53.                                     prompt preference. Added Edit menu and moved Preferences command
  54.                                     to there. Added support for scrolling the sender window.
  55.       <FW20>     2/21/97    jkl        Changed icon placement and management in sender window for
  56.                                     better multiple node support. Updated preferences menu to handle
  57.                                     menus and sound popup correctly.
  58.       <FW19>     2/19/97    jkl        Added Reply/Request options to SendFWXInfo. Set the state of the
  59.                                     sound notification popup menu according to the play sound check
  60.                                     box. Added play the sound after it is selected in the popup.
  61.                                     Corrected window zoom states. Made sure notification resources
  62.                                     are not purgeable.
  63.       <FW18>     2/13/97    jkl        Added a ForkWriteComplete to make sure a data buffer is
  64.                                     available before starting to read a new file fork.
  65.       <FW17>     2/11/97    jkl        Added read control and read data buffers and queues. Moved fwix
  66.                                     preferences to a file and closed file in all cases. Fixed
  67.                                     buttons in no sharing name dialog.
  68.       <FW16>     2/10/97    ES        Cleaned up deallocation code. Removed system heap allocations.
  69.       <FW15>      2/7/97    ES        Added call to GetNextFWXClientEvent in event loop.
  70.       <FW14>      2/6/97    ES        Changed to maintain list of all nodes that have been opened.
  71.                                     Will send quit notification to and close all nodes that have
  72.                                     been opened when quitting.
  73.       <FW13>      2/5/97    ES        Changed a CloseFWXDriver to CloseFWXNode.
  74.       <FW12>      2/2/97    jkl        Added Open Sharing Setup command to no machine name alert.
  75.                                     Modified menus and corrected menu state enabled/disabled
  76.                                     problems. Changed open drop folder command to make the finder
  77.                                     the foreground process. Corrected view size menu commands to
  78.                                     only work if that size is not the current size. Move the
  79.                                     preferences to a file. Correct the flahsing icon notification.
  80.                                     Moved NewPtrSys calls that are safe back to NewPtr.
  81.       <FW11>     1/29/97    ES        Changed InstallCompletionRoutineProcs to set up completion
  82.                                     routines to return status in D0. This is a workaround for a bug
  83.                                     in the File Manager.
  84.       <FW10>     1/27/97    ES        Added creation of FWControl PB queue.
  85.        <FW9>     1/27/97    jkl        Added timer routines to check for transfer disconnects and
  86.                                     errors. At idle check for timeout errors. Cleaned up from a
  87.                                     device removed event properly if a transfer is in progress.
  88.                                     Removed killio routine from CloseWindow, will let closing the
  89.                                     node handle it. Added check for transmit in progress and option
  90.                                     to quit or continue. Fixed stop button in progress dialog by
  91.                                     adding setport call. Modified view options menu to show check
  92.                                     marks instead of toggle title.
  93.        <FW8>     1/17/97    ES        Changed a CallFWXDriver to CallFWXNode. Changed NewPtrs to
  94.                                     NewPtrSyss because some buffers need to be held to be VM safe;
  95.                                     this is overkill, and really we just need to hold the right
  96.                                     buffers. Used NewPtrSysClear to allocate pRecvNode so that its
  97.                                     next pointer is nil.
  98.        <FW7>     1/16/97    jkl        Removed an open DebugStr call.
  99.        <FW6>     1/16/97    jkl        Added user interface features for alpha candidate. Added a
  100.                                     preferences dialog, changed window behavior to match normal
  101.                                     window behavior, changed fwix node icons to only be displayed if
  102.                                     the node has fwix running. Added receive file notification.
  103.        <FW5>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers. Fixed up hot
  104.                                     plugging and unplugging.
  105.        <FW4>    11/13/96    jkl        Moved from DoDriverIO interface to CallDriver. Implemented stop
  106.                                     transfer. Now Indentify receivers by name.
  107.        <FW3>     10/31/96    jkl        Fixed event handling when copy progress dialog
  108.                                        is being displayed. Added routine to update copy
  109.                                     progress dialog at idle time. Moved receive folder
  110.                                     check and initialization to application init time.
  111.        <FW2>     10/16/96    jkl        Modified queue handling to use OS Utils interrupt
  112.                                        safe queue routines. Created File Write Completion
  113.                                     routine proc. Removed reads and writes from idle
  114.                                     handler. The idle handler only checks to see if
  115.                                     the read or write is done. The reads and writes
  116.                                     are continued in the various completion routines.
  117.        <FW1>     10/2/96    jkl        Initial check-in.
  118. */
  119.  
  120. #include <QuickDraw.h>
  121. #include <SegLoad.h>
  122. #include <Types.h>
  123. #include <Memory.h>
  124. #include <Resources.h>
  125. #include <Fonts.h>
  126. #include <Menus.h>
  127. #include <Dialogs.h>
  128. #include <Events.h>
  129. #include <AppleEvents.h>
  130. #include <Processes.h>
  131. #include <Windows.h>
  132. #include <Errors.h>
  133. #include <Files.h>
  134. #include <Folders.h>
  135. #include <Script.h>
  136. #include <Devices.h>
  137. #include <TextUtils.h>
  138. #include <ToolUtils.h>
  139. #include <StandardFile.h>
  140. #include <Icons.h>
  141. #include <DiskInit.h>    
  142. #include <Notification.h>
  143. #include <Timer.h>
  144. #include <Sound.h>
  145.  
  146. #include "FWiX.h"
  147.  
  148. #include "FWiXmain.h"
  149. #include "FWiXdrag.h"
  150.  
  151. #include <stdio.h>
  152. char  debugStr[256];
  153. static pascal void FWDebugStr(
  154.     ConstStr255Param            debuggerMsg)
  155. {
  156. #ifdef FW_DEBUG_BUILD
  157. #if FW_DEBUG_BUILD
  158.     DebugStr (debuggerMsg);
  159. #endif
  160. #endif
  161. }
  162.  
  163. //////////////////////////////////////////////////////////////////////////////
  164. //
  165. // Internal procedure prototypes.
  166. //
  167.  
  168. static OSErr SendDeviceAddedToSelf (
  169.     FWXNodeID                theNodeID);
  170.  
  171. static OSErr SendDeviceRemovedToSelf (
  172.     FWXNodeID                theNodeID);
  173.     
  174. static pascal OSErr    HandleDeviceAddedEvent (
  175.     AppleEvent                *theAppleEvent,
  176.     AppleEvent                *reply,
  177.     SInt32                    handlerRefcon);
  178.  
  179. static OpenNodePtr GetNodeInfoFromID (
  180.     FWXNodeID                nodeID);
  181.  
  182. static pascal OSErr    HandleDeviceRemovedEvent (
  183.     AppleEvent                *theAppleEvent,
  184.     AppleEvent                *reply,
  185.     SInt32                    handlerRefcon);
  186.     
  187. void AdjustNodeIcons (
  188.     WindowDataPtr            pWinData,
  189.     Rect                    *windRect);
  190.  
  191. OSErr SendFWXInfo (
  192.     FWXNodeID                nodeID,
  193.     UInt32                    sendType);
  194.  
  195. OSErr SendFWXQuit (void);
  196.  
  197. static OSErr SetupFWXRead (
  198.     FWXNodeID                nodeID);
  199.  
  200. static OSErr GetNodeIDFromEvent (
  201.     AppleEvent                *pEvent,
  202.     FWXNodeID                *nodeID);
  203.     
  204. static OSErr GetNodeIDFromName (
  205.     FWXNodeID                *nodeID,
  206.     ConstStr255Param        nodeName);
  207.  
  208. static OSErr CreateWindow (void);
  209.  
  210. static void GetDisplayRect (
  211.     Rect                    *r,
  212.     WindowPtr                pWin,
  213.     WindowDataPtr            pWinData);
  214.  
  215. OSErr AdjustScrollBars (
  216.     WindowPtr                pWin,
  217.     Boolean                    adjustSizes);
  218.  
  219. OSErr InitRecvNode (
  220.     FWXNodeID                nodeID,
  221.     ConstStr255Param        nodeName);
  222.     
  223. static pascal void HandleReplyTimeout (
  224.     MyTMTaskPtr            pTMTask);
  225.  
  226. static pascal OSErr HandleGetNodeListEvent (
  227.     AppleEvent                *pAppleEvent,
  228.     AppleEvent                *pReplyEvent,
  229.     SInt32                    refCon);
  230.  
  231. static pascal OSErr HandleSendItemsEvent (
  232.     AppleEvent                *pAppleEvent,
  233.     AppleEvent                *pReplyEvent,
  234.     SInt32                    refCon);
  235.     
  236. static OSErr GetFSItemsFromEvent (
  237.     FSSpecPtr                *pSendItems,
  238.     AppleEvent                *pEvent,
  239.     UInt16                    *numItems);
  240.  
  241. static OSErr GetReceiveNodesFromEvent (
  242.     FWXNodeID                **pReceiveNodeIDList,
  243.     AppleEvent                *pAppleEvent,
  244.     UInt16                    *numNodes);
  245.     
  246. static pascal OSErr HandleOpenApplicationEvent (
  247.     AppleEvent                *pAppleEvent,
  248.     AppleEvent                *pReplyEvent,
  249.     SInt32                    refCon);
  250.     
  251. static pascal OSErr HandleOpenDocumentsEvent (
  252.     AppleEvent                *pAppleEvent,
  253.     AppleEvent                *pReplyEvent,
  254.     SInt32                    refCon);
  255.     
  256. static pascal OSErr HandleQuitApplicationEvent (
  257.     AppleEvent                *pAppleEvent,
  258.     AppleEvent                *pReplyEvent,
  259.     SInt32                    refCon);
  260.     
  261. static OSErr InstallAppleEventHandlers (void);
  262.  
  263. static OSErr InstallCompletionRoutineProcs (void);
  264.  
  265. static void DrawWindow (
  266.     WindowPtr                pWin);
  267.  
  268. static OSErr CreateMenus (void);
  269.  
  270. static void HandleCloseWindow (
  271.     WindowPtr                pWin);
  272.     
  273. static void HandleQuit (void);
  274.  
  275. static void HandleMenuCommand (
  276.     SInt32                    menuVal);
  277.     
  278. OSErr OpenDropFolder(void);
  279.  
  280. static OSErr OpenSharingSetup(void);
  281.  
  282. static OSErr HandleViewSize(
  283.     SInt16                    menuItem);
  284.  
  285. static void HandleMouseDownEvent (
  286.     EventRecord                *pEventRecord);
  287.  
  288. static pascal void HandleThumbScroll (
  289.     ControlHandle            scrollCtl,
  290.     WindowPtr                pWin,
  291.     Point                    mouse);
  292.  
  293. static pascal void HandleScrollAction (
  294.     ControlHandle            scrollCtl,
  295.     SInt16                    part);
  296.  
  297. static void HandleGrowWindow(
  298.     WindowPtr                    pWin,
  299.     Point                        clickLoc);
  300.  
  301. static void HandleZoomWindow(
  302.     WindowPtr                    pWin,
  303.     SInt16                        whichZoom);
  304.  
  305. void StopTransfer (
  306.     RecvNodePtr                    pNode);
  307.  
  308. static void HandleKeyEvent (
  309.     EventRecord                *pEventRecord);
  310.  
  311. static void HandleOSEvent (
  312.     EventRecord                *pEventRecord);
  313.  
  314. static void HandleEvent (
  315.     EventRecord                *theEvent);
  316.  
  317. static void HandleActivate (
  318.     WindowPtr                pWin,
  319.     Boolean                    becomingActive);
  320.  
  321. static Boolean IsAppWindow (
  322.     WindowPtr                pWin);
  323.     
  324. static pascal Boolean HandleAlertEventFilter (
  325.     DialogPtr                pDlog,
  326.     EventRecord                *pEvent,
  327.     SInt16                    *itemHit);
  328.  
  329. static OSErr SetupFWXNode (void);
  330.  
  331. static OSErr InitNotification (void);
  332.  
  333. pascal void HandleNotifyResponse (
  334.     NMRecPtr                pNMRequest);
  335.  
  336.  
  337. static OSErr SetupIOQueue (void);
  338.  
  339. static OSErr FWXInit (void);
  340.     
  341. static OSErr FWXDispose (void);
  342.  
  343. //////////////////////////////////////////////////////////////////////////////
  344. //
  345. // External procedure prototypes.
  346. //
  347.  
  348. extern OSErr InstallDragHandlers (void);    
  349.  
  350. extern void RemoveDragHandlers (void);
  351.     
  352. extern pascal OSErr HandleAEFileSpecList (
  353.     AppleEvent                *pAEvent,
  354.     AppleEvent                 *pReply,
  355.     SInt32                    refCon);
  356.  
  357. extern OSErr GetNodeDragRect (
  358.     WindowPtr                pWin,
  359.     SInt16                    spaceIndex,
  360.     Rect                    *iconRect,
  361.     Rect                    *textRect);
  362.  
  363. extern void HandleReceive (void);
  364.  
  365. extern void HandleForkReadComplete (void);
  366.  
  367. extern OSErr FSGetCatInfo (
  368.     FSSpec                     *fsSpec,
  369.     CInfoPBPtr                result);
  370.  
  371. extern void UpdateProgressBar (
  372.     WindowPtr            theWindow,
  373.     SInt16                itemNo);
  374.  
  375. extern OSErr GetNodeName (
  376.     WindowPtr            pWin,
  377.     SInt16                spaceIndex,
  378.     StringPtr            *pString);
  379.     
  380. extern void CleanupCopyDialog(
  381.     WindowPtr            theDialog);
  382.  
  383. extern OSErr GetNodeInfo (
  384.     FWXNodeID            nodeID,
  385.     RecvNodePtr            *pRecvNode);
  386.  
  387. extern OSErr HandleStopTransfer(
  388.     CurFileInfoPtr        pCurFileInfo);
  389.     
  390. extern OSErr GetCurFileInfo(
  391.     FWXNodeID            sourceID,
  392.     CurFileInfoPtr        *hCurFileInfo,
  393.     Boolean                createNew);
  394.  
  395. extern OSErr InitRecvFolder(
  396.     SInt32                *dirID);
  397.  
  398.  
  399. //////////////////////////////////////////////////////////////////////////////
  400. //
  401. //    Globals JKL *** these all need to be cleaned up
  402. //
  403. #ifndef __MWERKS__
  404. QDGlobals            qd;
  405. #endif
  406.  
  407. FWXAppDataPtr        gpFWXAppData = nil;
  408.  
  409. Boolean                queuesInitialized = false;
  410. QHdr                gSendQHdr;
  411. QHdr                gAESendQHdr;
  412. QHdr                gReceiveQHdr;
  413. QHdr                gFileReadQHdr;
  414. QHdr                gFWControlQHdr;
  415. QHdr                gFWWriteQHdr;
  416. QHdr                gCurFileQHdr;
  417. SInt16                gCurForkRefNum;
  418.  
  419. Boolean             gSendingFile,
  420.                     gCheckingTransfer,
  421.                     gSendingDataFork,
  422.                     gSendingResFork,
  423.                     gForkWriteComplete,
  424.                     gForkComplete;
  425.  
  426. FWXNodeID    gSendError;
  427. FWXNodeID    gReceiveError;
  428.                     
  429. //////////////////////////////////////////////////////////////////////////////
  430. //
  431. //    SendDeviceAddedToSelf
  432. //
  433. //    Send a firewire device added appleevent to us
  434. //
  435. static OSErr SendDeviceAddedToSelf(
  436.     FWXNodeID                theNodeID)
  437. {
  438.     AppleEvent                send;
  439.     AppleEvent                reply;
  440.     AEDesc                    selfTarget;
  441.     ProcessSerialNumber        psn;
  442.     OSErr                    err;
  443.  
  444.     selfTarget.dataHandle = nil;
  445.     send.dataHandle = nil;
  446.  
  447.     // Get our address
  448.     GetCurrentProcess(&psn);
  449.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  450.     if (err != noErr)
  451.         return err;
  452.             
  453.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceAdded, &selfTarget, 
  454.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  455.     if (err != noErr) {
  456.         AEDisposeDesc(&selfTarget);
  457.         return err;
  458.     }
  459.     
  460.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  461.  
  462.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  463.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  464.  
  465.     if (err != noErr) {
  466.         AEDisposeDesc(&selfTarget);
  467.         AEDisposeDesc(&send);
  468.     }
  469.  
  470.     return err;
  471. }
  472.  
  473. //////////////////////////////////////////////////////////////////////////////
  474. //
  475. //    SendDeviceRemovedToSelf
  476. //
  477. //    Send a firewire device removed appleevent to us
  478. //
  479. static OSErr SendDeviceRemovedToSelf(
  480.     FWXNodeID                theNodeID)
  481. {
  482.     AppleEvent                send;
  483.     AppleEvent                reply;
  484.     AEDesc                    selfTarget;
  485.     ProcessSerialNumber        psn;
  486.     OSErr                    err;
  487.  
  488.     selfTarget.dataHandle = nil;
  489.     send.dataHandle = nil;
  490.  
  491.     // Get our address
  492.     GetCurrentProcess(&psn);
  493.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  494.     if (err != noErr)
  495.         return err;
  496.             
  497.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceRemoved, &selfTarget, 
  498.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  499.     if (err != noErr) {
  500.         AEDisposeDesc(&selfTarget);
  501.         return err;
  502.     }
  503.         
  504.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  505.  
  506.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  507.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  508.  
  509.     if (err != noErr) {
  510.         AEDisposeDesc(&selfTarget);
  511.         AEDisposeDesc(&send);
  512.     }
  513.     
  514.     return err;
  515. }
  516.  
  517. //////////////////////////////////////////////////////////////////////////////
  518. //
  519. //    HandleDeviceAddedEvent
  520. //
  521. //    Called when a new FireWire File Exchange receiver connects to the bus.
  522. //    Add it to the list of open nodes. Prime it with receive buffers. Send our
  523. //    machine info to it.
  524. //
  525. static pascal OSErr    HandleDeviceAddedEvent (
  526.     AppleEvent            *theAppleEvent,
  527.     AppleEvent            *reply,
  528.     long                handlerRefcon)
  529. {
  530.     WindowPtr            pWin;
  531.     WindowDataPtr        pWinData;
  532.     OpenNodePtr            pOpenNode;
  533.     OpenNodePtr            pTempOpenNode;
  534.     FWXNodeID            nodeID;
  535.     OSErr                err = noErr;
  536.     
  537.     //    get node id out of appleevent
  538.     err = GetNodeIDFromEvent(theAppleEvent, &nodeID);
  539.         
  540.     if (err == noErr)
  541.         pOpenNode = GetNodeInfoFromID(nodeID);
  542.     
  543.     if ((err == noErr) && (pOpenNode == nil))
  544.     {
  545.         pWin = gpFWXAppData->pSenderWindow;
  546.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  547.         if (pWinData == nil)
  548.             err = memFullErr;
  549.         
  550.         if (err == noErr)
  551.         {
  552.             // create open node record.
  553.             pOpenNode = (OpenNodePtr) NewPtrClear(sizeof(OpenNodeRecord));
  554.             if (pOpenNode != nil)
  555.                 pOpenNode->nodeID = nodeID;
  556.             else
  557.                 err = memFullErr;
  558.         }
  559.             
  560.         if (err == noErr)
  561.             // open the node
  562.             err = OpenFWXNode(nodeID);
  563.                 
  564.         if (err == noErr)
  565.         {
  566.             pWinData->numOpenNodes++;
  567.         
  568.             // add the node to the open list
  569.             // if this is the first node, just point to it
  570.             if (pWinData->numOpenNodes == 1)
  571.                 pWinData->pOpenNodeList = pOpenNode;
  572.             else
  573.             {
  574.                 // it is not the first node, traverse the list, add new node to the end
  575.                 pTempOpenNode = pWinData->pOpenNodeList;
  576.                 while (pTempOpenNode->pNextNode != nil)            
  577.                     pTempOpenNode = pTempOpenNode->pNextNode;
  578.                 pTempOpenNode->pNextNode = pOpenNode;
  579.                 pOpenNode->pPreviousNode = pTempOpenNode;
  580.             }
  581.         }
  582.  
  583.         if (err != noErr)
  584.         {
  585.             // clean up on error
  586.             if (pOpenNode != nil)
  587.                 DisposePtr((Ptr) pOpenNode);
  588.         }
  589.  
  590.         if (err == noErr)
  591.             // issue reads to prime node with receive buffers
  592.             err = SetupFWXRead(nodeID);
  593.             
  594.         if (err == noErr)
  595.             // send the new node our name and id info
  596.             err = SendFWXInfo(nodeID, kNodeInfoRequest);
  597.     
  598.         if (err == memFullErr)
  599.             HandleStopAlert(kMemoryErrorAlertID);
  600.         else if (err != noErr)
  601.             // JKL *** need a generic error alert mechanism
  602.             HandleStopAlert(kUnknownErrAlertID);
  603.     }
  604.     return err;
  605. }
  606.  
  607. ////////////////////////////////////////////////////////////////////////////////
  608. //
  609. //    GetNodeInfoFromID
  610. //
  611. //    Search open node list for node record corresponding to node id.
  612. //
  613. static OpenNodePtr GetNodeInfoFromID (
  614.     FWXNodeID            nodeID)
  615. {
  616.     WindowDataPtr        pWinData;
  617.     OpenNodePtr            pOpenNode;
  618.     Boolean                found;
  619.     
  620.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  621.     pOpenNode = pWinData->pOpenNodeList;
  622.  
  623.     found = false;
  624.     while ((pOpenNode != nil) && (!found))
  625.     {
  626.         if (pOpenNode->nodeID == nodeID)
  627.             found = true;
  628.         else
  629.             pOpenNode = pOpenNode->pNextNode;
  630.     }
  631.     return pOpenNode;
  632. }
  633.  
  634. ////////////////////////////////////////////////////////////////////////////////
  635. //
  636. //    SendFWXInfo
  637. //
  638. //    Send our info to another node. Get the sharing setup machine name out
  639. //    of string resource.
  640. //
  641. OSErr SendFWXInfo(
  642.     FWXNodeID            nodeID,
  643.     UInt32                sendType)
  644. {
  645.     Handle                hString;
  646.     IOParamPtr            pIOPb;
  647.     FWXPacketPtr        pPktInfo;
  648.     SInt16                curResFile;
  649.     OSErr                err = noErr;
  650.  
  651.     // Get the sharing setup macintosh name
  652.     curResFile = CurResFile();
  653.     UseResFile(kSystemResFile);
  654.     hString = Get1Resource('STR ', kNetworkNameID);
  655.  
  656.     if ((hString != nil) && (**hString != 0))
  657.     {
  658.         FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  659.         if (pIOPb != nil)
  660.         {
  661.             SetupFWControlPB(pIOPb);
  662.             // SetupFWControlPB will leave an invalid node id in nameptr at this point
  663.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  664.             
  665.             // copy the string into the data buffer
  666.             pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  667.             pPktInfo->packetType = sendType;
  668.             pIOPb->ioMisc = (Ptr) sendType;
  669.             BlockMove(*hString, (Ptr) &pPktInfo->packetData, **hString + 1);
  670.             pIOPb->ioReqCount = **hString + 1 + 4;    // length of string plus packet header
  671.             
  672.             err = CallFWXNode(pIOPb);
  673.         }
  674.         else
  675.         {
  676.             err = qErr;
  677.             FWDebugStr("\pNo buffer for SendFWXInfo");
  678.         }
  679.  
  680.         ReleaseResource(hString);
  681.     }
  682.     else
  683.     {
  684.         HandleStopAlert(kNoNameAlertID);
  685.         ExitToShell();
  686.     }
  687.     UseResFile(curResFile);
  688.     return err;
  689. }
  690.  
  691. ////////////////////////////////////////////////////////////////////////////////
  692. //
  693. //    SendFWXQuit
  694. //
  695. //    Send a quit notification to each receive node.
  696. //
  697. OSErr SendFWXQuit(void)
  698. {
  699.     WindowDataPtr        pWinData;
  700.     OpenNodePtr            pOpenNode;
  701.     IOParamPtr            pIOPb;
  702.     FWXPacketPtr        pPktInfo;
  703.     SInt16                i;
  704.     OSErr                err = noErr;
  705.  
  706.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  707.     if (pWinData != nil)
  708.     {        
  709.         pOpenNode = pWinData->pOpenNodeList;
  710.         for (i = 0; i < pWinData->numOpenNodes; i++)
  711.         {
  712.             FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  713.             if (pIOPb != nil)
  714.             {
  715.                 SetupFWControlPB(pIOPb);
  716.                 // SetupFWWritePB will leave an invalid driver id in nameptr at this point
  717.                 pIOPb->ioNamePtr = (StringPtr) pOpenNode->nodeID;
  718.                 
  719.                 // copy the string into the data buffer
  720.                 pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  721.                 pPktInfo->packetType = kQuitNotify;
  722.                 pIOPb->ioMisc = (Ptr) kQuitNotify;
  723.                 pIOPb->ioReqCount = 4;
  724.                 
  725.                 err = CallFWXNode(pIOPb);
  726.             }
  727.             else
  728.             {
  729.                 err = qErr;
  730.                 FWDebugStr("\pNo buffer for SendFWXQuit");
  731.             }
  732.             pOpenNode = (OpenNodePtr) pOpenNode->pNextNode;
  733.         }
  734.     }
  735.     else
  736.         err = resNotFound;
  737.  
  738.     return err;
  739. }
  740.  
  741. ////////////////////////////////////////////////////////////////////////////////
  742. //
  743. //    SetupFWXRead
  744. //
  745. //    Create control buffers and a data buffer and pass the buffers to
  746. //    the driver.
  747. //
  748. static OSErr SetupFWXRead(
  749.     FWXNodeID            nodeID)
  750. {
  751.     IOParamPtr            pIOPb;
  752.     SInt16                i;
  753.     OSErr                err = noErr;
  754.  
  755.     // create control receive parameter block, receive buffer, and issue read
  756.     for (i=0; i < kFWReadControlBufs; i++) {
  757.         pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  758.         if (pIOPb != nil) {
  759.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  760.         } else {
  761.             FWDebugStr("\pOut of memory, SetupReadQueue");
  762.             err = memFullErr;
  763.             break;
  764.         }
  765.         
  766.         pIOPb->ioBuffer = NewPtr(kFWReadControlBufSize);
  767.         if (pIOPb->ioBuffer != nil) {
  768.             HoldMemory (pIOPb->ioBuffer, kFWReadControlBufSize);
  769.         } else {
  770.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  771.             DisposePtr((Ptr) pIOPb);
  772.             FWDebugStr("\pOut of memory, SetupReadQueue");
  773.             err = memFullErr;
  774.             break;
  775.         }
  776.         
  777.         // set up parameter block
  778.         pIOPb->ioNamePtr = (StringPtr) nodeID;
  779.         pIOPb->ioTrap = kFWXRead;
  780.         pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  781.         pIOPb->ioReqCount = kFWReadControlBufSize;
  782.  
  783.         err = CallFWXNode(pIOPb);
  784.         if (err != noErr) {
  785.             sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  786.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  787.             break;
  788.         }
  789.     }
  790.     
  791.     if (err == noErr) {
  792.         // setup the data read parameter blocks
  793.         for (i=0; i < kFWReadDataBufs; i++) {
  794.             pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  795.             if (pIOPb != nil) {
  796.                 HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  797.             } else {
  798.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  799.                 err = memFullErr;
  800.                 break;
  801.             }
  802.             
  803.             pIOPb->ioBuffer = NewPtr(kFWReadDataBufSize);
  804.             if (pIOPb->ioBuffer != nil) {
  805.                 HoldMemory (pIOPb->ioBuffer, kFWReadDataBufSize);
  806.             } else {
  807.                 UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  808.                 DisposePtr((Ptr) pIOPb);
  809.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  810.                 err = memFullErr;
  811.                 break;
  812.             }
  813.             
  814.             // set up parameter block
  815.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  816.             pIOPb->ioTrap = kFWXRead;
  817.             pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  818.             pIOPb->ioReqCount = kFWReadDataBufSize;
  819.             pIOPb->ioMisc = (Ptr) kForkData;
  820.         
  821.             err = CallFWXNode(pIOPb);
  822.             if (err != noErr) {
  823.                 sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  824.                 FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  825.                 break;
  826.             }
  827.         }
  828.     }
  829.     return err;
  830. }
  831.  
  832. ////////////////////////////////////////////////////////////////////////////////
  833. //
  834. //    GetNodeIDFromEvent
  835. //
  836. //    Get the firewire file exchange node ID
  837. //    out of the device added or removed apple event
  838. //
  839. static OSErr GetNodeIDFromEvent(
  840.     AppleEvent            *pAEvent,
  841.     FWXNodeID            *nodeID)
  842. {
  843.     OSErr                err;
  844.     DescType            returnType;
  845.     Size                returnSize;
  846.  
  847.     err = AEGetParamPtr(pAEvent, kAEFWXNodeIDKey, kAEFWXNodeIDType, &returnType, 
  848.                         (Ptr) nodeID, sizeof(FWXNodeID), &returnSize);
  849.     return err;
  850. }
  851.  
  852. ////////////////////////////////////////////////////////////////////////////////
  853. //
  854. //    CreateWindow
  855. //
  856. //    Creates firwire sender window. Called when the first
  857. //    FireWire Exchange receive node is connected to the bus.
  858. //
  859.  
  860. static OSErr CreateWindow (void)
  861. {
  862.     WindowRef            pWin;
  863.     GrafPtr                curPort;
  864.     WindowDataPtr        pWinData;
  865.     MenuHandle            hMenu;
  866.     Rect                winRect;
  867.     OSErr                err = noErr;
  868.     
  869.     // open the window
  870.     pWin = GetNewCWindow(kWindowResourceID, nil, (WindowRef) -1);
  871.     
  872.     if (pWin == nil)
  873.         err = ResError();
  874.     else
  875.     {
  876.         // position and size window
  877.         err = GetWindowPos(&winRect);
  878.         if (err == noErr)
  879.         {
  880.             MoveWindow(pWin, winRect.left, winRect.top, false);
  881.             SizeWindow(pWin, winRect.right - winRect.left, winRect.bottom - winRect.top, false);
  882.         }
  883.         else
  884.             err = noErr;    // don't care if resource problem
  885.         
  886.         // Allocate window data structure
  887.         pWinData = (WindowDataPtr) NewPtrClear(sizeof(WindowData));
  888.         if (pWinData != nil)
  889.         {        
  890.             pWinData->numOpenNodes = 0;
  891.             pWinData->pOpenNodeList = nil;
  892.             pWinData->numRecvNodes = 0;
  893.             pWinData->pRecvNodeList = nil;
  894.             pWinData->hVScrollBar = GetNewControl(kVScrollBar, pWin);
  895.             if (pWinData->hVScrollBar == nil)
  896.                 err = ResError();
  897.             pWinData->hHScrollBar = GetNewControl(kHScrollBar, pWin);
  898.             if (pWinData->hHScrollBar == nil)
  899.                 err = ResError();
  900.             
  901.             SetWRefCon(pWin, (SInt32) pWinData);
  902.             if (err == noErr)
  903.                 AdjustScrollBars(pWin, true);
  904.         }
  905.         else
  906.         {
  907.             err = memFullErr;
  908.             DisposeWindow(pWin);
  909.         }
  910.     }
  911.     gpFWXAppData->pSenderWindow = pWin;
  912.     if (err == noErr)
  913.     {
  914.         GetPort(&curPort);
  915.         SetPort(pWin);
  916.         TextSize(9);
  917.         ClipRect(&qd.screenBits.bounds);
  918.         SetPort(curPort);
  919.     }
  920.     if (err == noErr)
  921.     {
  922.         if (gpFWXAppData->fwixPrefs & kIconView)
  923.         {
  924.             pWinData->windowView = kSmallIconView;
  925.             hMenu = GetMenuHandle(kViewMenuID);
  926.             SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  927.             SetItemMark(hMenu, kIconMenuItem, noMark);
  928.         }
  929.         else
  930.             pWinData->windowView = kLargeIconView;
  931.     }
  932.  
  933.     return err;
  934. }
  935.  
  936. //////////////////////////////////////////////////////////////////////////////
  937. //
  938. //    GetDisplayRect
  939. //
  940. //    Calculate the rectangle needed to display all of the sender window items.
  941. //
  942. static void GetDisplayRect (
  943.     Rect                    *r,
  944.     WindowPtr                pWin,
  945.     WindowDataPtr            pWinData)
  946. {
  947.     GrafPtr                    curPort;
  948.     Rect                    iconRect, textRect;
  949.     SInt16                    row, column;
  950.     SInt16                    index, count;
  951.  
  952.     GetPort(&curPort);
  953.     SetPort(pWin);
  954.     TextSize(9);
  955.  
  956.     if (pWinData->windowView == kLargeIconView)
  957.     {
  958.         row = pWinData->numRecvNodes % kLargeRowCount;
  959.         column = pWinData->numRecvNodes / kLargeRowCount;
  960.         if (column == 0)
  961.             count = row;
  962.         else
  963.             count = kLargeRowCount;
  964.             
  965.         // get smallest left value
  966.         for (index = 1; index <= count; index++)
  967.         {
  968.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  969.             if (textRect.left < iconRect.left)
  970.             {
  971.                 if (textRect.left < r->left)
  972.                     r->left = textRect.left;
  973.             }
  974.             else
  975.             {
  976.                 if (iconRect.left < r->left)
  977.                     r->left = iconRect.left;
  978.             }
  979.         }
  980.  
  981.         // get smallest top value
  982.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  983.         if (iconRect.top < r->top)
  984.             r->top = iconRect.top;
  985.  
  986.         // get largest bottom value from lowest icon in row
  987.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  988.         if (textRect.bottom > r->bottom)
  989.             r->bottom = textRect.bottom;
  990.             
  991.         // get largest right value by checking space needed for far right column
  992.         for (index = ((column * kLargeRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  993.         {
  994.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  995.             if (textRect.right > iconRect.right)
  996.             {
  997.                 if (textRect.right > r->right)
  998.                     r->right = textRect.right;
  999.             }
  1000.             else
  1001.             {
  1002.                 if (iconRect.right > r->right)
  1003.                     r->right = iconRect.right;
  1004.             }
  1005.         }                
  1006.     }
  1007.     else
  1008.     {
  1009.         row = pWinData->numRecvNodes % kSmallRowCount;
  1010.         column = pWinData->numRecvNodes / kSmallRowCount;
  1011.         if (column == 0)
  1012.             count = row;
  1013.         else
  1014.             count = kSmallRowCount;
  1015.  
  1016.         // get smallest top left value
  1017.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  1018.         if (iconRect.top < r->top)
  1019.             r->top = iconRect.top;
  1020.         if (iconRect.left < r->left)
  1021.             r->left = iconRect.left;
  1022.  
  1023.         // get largest bottom value from lowest icon in row
  1024.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  1025.         if (iconRect.bottom > r->bottom)
  1026.             r->bottom = iconRect.bottom;
  1027.             
  1028.         // get largest right value by checking space needed for far right column
  1029.         for (index = ((column * kSmallRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  1030.         {
  1031.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  1032.             if (textRect.right > r->right)
  1033.                 r->right = textRect.right;
  1034.         }                
  1035.     }    
  1036.     SetPort(curPort);
  1037. }
  1038.  
  1039. //////////////////////////////////////////////////////////////////////////////
  1040. //
  1041. //    AdjustScrollBars
  1042. //
  1043. //    Adjust and size scroll bars
  1044. //
  1045. OSErr AdjustScrollBars (
  1046.     WindowPtr                pWin,
  1047.     Boolean                    adjustSizes)
  1048. {
  1049.     WindowDataPtr            pWinData;
  1050.     Rect                    viewRect,        // view able area in window
  1051.                             displayRect;    // area needed to display node list
  1052.     Rect                    ctlRect;
  1053.     SInt16                    displayH, displayV, viewH, viewV;
  1054.     SInt16                    ctlVal;
  1055.     OSErr                    err = noErr;
  1056.  
  1057.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1058.     if (pWinData != nil)
  1059.     {
  1060.         // calculate view space available
  1061.         viewRect = pWin->portRect;
  1062.         viewRect.bottom -= kScrollBarAdjust;
  1063.         viewRect.right -= kScrollBarAdjust;
  1064.         displayRect = viewRect;
  1065.         
  1066.         GetDisplayRect (&displayRect, pWin, pWinData);
  1067.         displayH = displayRect.right - displayRect.left;
  1068.         viewH = viewRect.right - viewRect.left;
  1069.         
  1070.         if (displayH > viewH)
  1071.         {
  1072.             SetControlMaximum (pWinData->hHScrollBar, displayH - viewH);
  1073.             ctlVal = GetControlValue(pWinData->hHScrollBar);
  1074.             SetControlValue (pWinData->hHScrollBar, ctlVal + (viewRect.left - displayRect.left));
  1075.         }
  1076.         else
  1077.         {
  1078.             SetControlMaximum (pWinData->hHScrollBar, 0);
  1079.             SetControlValue (pWinData->hHScrollBar, 0);
  1080.         }
  1081.     
  1082.         displayV = displayRect.bottom - displayRect.top;
  1083.         viewV = viewRect.bottom - viewRect.top;
  1084.         if (displayV > viewV)
  1085.         {
  1086.             SetControlMaximum (pWinData->hVScrollBar, displayV - viewV);
  1087.             ctlVal = GetControlValue(pWinData->hVScrollBar);
  1088.             SetControlValue (pWinData->hVScrollBar, ctlVal + (viewRect.top - displayRect.top));
  1089.         }
  1090.         else
  1091.         {
  1092.             SetControlMaximum (pWinData->hVScrollBar, 0);
  1093.             SetControlValue (pWinData->hVScrollBar, 0);
  1094.         }
  1095.         
  1096.         if (adjustSizes)
  1097.         {
  1098.             // position and size vertical scroll bar
  1099.             ctlRect = pWin->portRect;
  1100.             MoveControl (pWinData->hVScrollBar,
  1101.                          ctlRect.right - kScrollBarAdjust,
  1102.                          -1);
  1103.             SizeControl (pWinData->hVScrollBar,
  1104.                          kScrollBarWidth,
  1105.                          (ctlRect .bottom - ctlRect.top) - (kScrollBarAdjust - kScrollBarTweek));
  1106.     
  1107.             // position and size horizontal scroll bar
  1108.             MoveControl (pWinData->hHScrollBar,
  1109.                          -1,
  1110.                          ctlRect.bottom - kScrollBarAdjust);
  1111.             SizeControl (pWinData->hHScrollBar,
  1112.                          (ctlRect.right - ctlRect.left) - (kScrollBarAdjust - kScrollBarTweek),
  1113.                          kScrollBarWidth);
  1114.         }
  1115.     }
  1116.     else
  1117.         err = resNotFound;
  1118.     return  err;
  1119. }
  1120.  
  1121. //////////////////////////////////////////////////////////////////////////////
  1122. //
  1123. //    InitRecvNode
  1124. //
  1125. //    Set up the node drag rectangles and node list.
  1126. //
  1127. OSErr InitRecvNode (
  1128.     FWXNodeID                nodeID,
  1129.     ConstStr255Param        nodeName)
  1130. {
  1131.     WindowPtr                pWin;
  1132.     WindowDataPtr            pWinData;
  1133.     RecvNodePtr                pRecvNode;
  1134.     RecvNodePtr                pTempRecvNode;
  1135.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1136.     SInt16                    row, column;    
  1137.     SInt16                    sLoc, sWidth;    
  1138.     OSErr                    err = noErr;
  1139.     
  1140.     pWin = gpFWXAppData->pSenderWindow;
  1141.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1142.     if (pWinData == nil)
  1143.         return memFullErr;
  1144.         
  1145.     pRecvNode = (RecvNodePtr) NewPtrClear(sizeof(RecvNodeRecord));
  1146.     if (pRecvNode == nil)
  1147.         return memFullErr;
  1148.  
  1149.     pRecvNode->pReplyTimer = (MyTMTaskPtr) NewPtrClear(sizeof(MyTMTask));
  1150.     if (pRecvNode->pReplyTimer == nil)
  1151.         return memFullErr;
  1152.     else
  1153.     {
  1154.         pRecvNode->pReplyTimer->timerTask.tmAddr = NewTimerProc(HandleReplyTimeout);
  1155.         if (pRecvNode->pReplyTimer->timerTask.tmAddr == nil)
  1156.             return memFullErr;
  1157.             
  1158.         InsTime((QElemPtr) pRecvNode->pReplyTimer);
  1159.     }
  1160.  
  1161.     // init values
  1162.     pRecvNode->nodeID = nodeID;
  1163.     BlockMove(nodeName, pRecvNode->nodeName, nodeName[0] + 1);
  1164.     sWidth = StringWidth(pRecvNode->nodeName);
  1165.  
  1166.     // setup node drag rectangle
  1167.     if (pWinData->windowView == kLargeIconView)
  1168.     {
  1169.         row = pWinData->numRecvNodes % kLargeRowCount;
  1170.         column = pWinData->numRecvNodes / kLargeRowCount;
  1171.         rctLeft = kLargeHFill + (column * kLargeHSize);
  1172.         rctRight = rctLeft + kLargeIconFill;
  1173.         rctTop = kLargeVFill + (row * kLargeVSize);
  1174.         rctBottom = rctTop + kLargeIconFill;
  1175.  
  1176.         sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1177.         sLoc -= ((sWidth / 2) + 2);
  1178.         SetRect(&pRecvNode->recvNodeTextRect,
  1179.                 sLoc,
  1180.                 rctBottom,
  1181.                 sLoc + sWidth + 3,
  1182.                 rctBottom + 13); 
  1183.     }
  1184.     else
  1185.     {
  1186.         row = pWinData->numRecvNodes % kSmallRowCount;
  1187.         column = pWinData->numRecvNodes / kSmallRowCount;
  1188.         rctLeft = kSmallHFill + (column * kSmallHSize);
  1189.         rctRight = rctLeft + kSmallIconFill;
  1190.         rctTop = kSmallVFill + (row * kSmallVSize);
  1191.         rctBottom = rctTop + kSmallIconFill;
  1192.  
  1193.         SetRect(&pRecvNode->recvNodeTextRect,
  1194.                 rctRight + 2,
  1195.                 rctBottom - 15,
  1196.                 rctRight + sWidth + 5,
  1197.                 rctBottom - 2); 
  1198.     }    
  1199.     SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom); 
  1200.     
  1201.     // increment node count after updating rectangles
  1202.     pWinData->numRecvNodes++;
  1203.     
  1204.     // add the node to the list, if the the first node, just point to it
  1205.     if (pWinData->numRecvNodes == 1)
  1206.         pWinData->pRecvNodeList = pRecvNode;
  1207.     else
  1208.     {
  1209.     // it is not the first node, traverse the list, add new node to the end
  1210.         pTempRecvNode = pWinData->pRecvNodeList;
  1211.         while (pTempRecvNode->pNextNode != nil)
  1212.             pTempRecvNode = pTempRecvNode->pNextNode;
  1213.         pTempRecvNode->pNextNode = pRecvNode;
  1214.         pRecvNode->pPreviousNode = pTempRecvNode;
  1215.     }
  1216.  
  1217.     AdjustScrollBars(pWin, false);
  1218.  
  1219.     return err;
  1220. }
  1221.  
  1222. //////////////////////////////////////////////////////////////////////////////
  1223. //
  1224. //    HandleReplyTimeout
  1225. //
  1226. //    For various communications with nodes, fwix posts a timer to wait for
  1227. //    a reply. If no reply is received this task is executed.
  1228. // 
  1229. //    JKL *** needs to have a variable timer to increase timeout period from
  1230. //    a few seconds up to a couple of minutes and eventually give up
  1231. // 
  1232. static pascal void HandleReplyTimeout (
  1233.     MyTMTaskPtr            pTMTask)
  1234. {
  1235.     gSendError = pTMTask->nodeID;
  1236. }
  1237.  
  1238. //////////////////////////////////////////////////////////////////////////////
  1239. //
  1240. //    HandleDeviceRemovedEvent
  1241. //
  1242. //    Called when a FWIX receiver node disconnects from the bus. If the node
  1243. //    had fwix open, clean up the node info and any sends. Otherwise close the node.
  1244. // 
  1245. //    JKL *** what if we are receiving data from this node? handle by HandleReceive timeout?
  1246. static pascal OSErr    HandleDeviceRemovedEvent (
  1247.     AppleEvent                *theAppleEvent,
  1248.     AppleEvent                *reply,
  1249.     long                    handlerRefcon)
  1250. {
  1251.     WindowDataPtr            pWinData;
  1252.     GrafPtr                    curPort;
  1253.     GrafPtr                    pWindowPort;
  1254.     RecvNodePtr                pTempRecvNode;
  1255.     OpenNodePtr                pTempOpenNode;
  1256.     FWXNodeID                targetNodeID;
  1257.     TxFSSpecPtr                pTxItem;
  1258.     OSErr                    err;
  1259.     Boolean                    foundNodeID;
  1260.  
  1261.     err = GetNodeIDFromEvent(theAppleEvent, &targetNodeID);
  1262.     if ((err == noErr) && (gSendingFile || gCheckingTransfer))
  1263.     {
  1264.         // if we are sending a file to the removed node,
  1265.         // dismiss the dialog, clean up send queue, and alert user
  1266.         if (targetNodeID == ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode)
  1267.         {
  1268.             gCheckingTransfer = false;
  1269.             gSendingFile = false;
  1270.             gForkComplete = true;
  1271.             gForkWriteComplete = true;
  1272.             CleanupCopyDialog(FrontWindow());
  1273.             if (gSendingDataFork || gSendingResFork)
  1274.             {
  1275.                 gSendingDataFork = false;
  1276.                 gSendingResFork = false;
  1277.                 FSClose(gCurForkRefNum);
  1278.             }
  1279.     
  1280.             // dequeue and dispose of all file queue entries
  1281.             pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1282.             while (pTxItem != nil)
  1283.             {
  1284.                 Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  1285.                 DisposePtr((Ptr) pTxItem->pFSSpec);
  1286.                 DisposePtr((Ptr) pTxItem);
  1287.  
  1288.                 // get another queue item
  1289.                 pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1290.             }
  1291.             
  1292.             GetNodeInfo(targetNodeID, &pTempRecvNode);
  1293.             ParamText(pTempRecvNode->nodeName, "\p", "\p", "\p");
  1294.             HandleCautionAlert(kNodeDisconnectAlertID);
  1295.         }
  1296.     }
  1297.     
  1298.     // Get the window data record
  1299.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1300.     
  1301.     // Traverse the open node list to find the node record for the nodeID
  1302.     foundNodeID = false;
  1303.     pTempOpenNode = pWinData->pOpenNodeList;
  1304.     while ((pTempOpenNode != nil) && (!foundNodeID))
  1305.     {
  1306.         if (pTempOpenNode->nodeID == targetNodeID)
  1307.         {
  1308.             foundNodeID = true;
  1309.             break;
  1310.         }
  1311.         pTempOpenNode = pTempOpenNode->pNextNode;    
  1312.     }
  1313.  
  1314.     if (foundNodeID)
  1315.     {    
  1316.         // handle removing the node from the open node list
  1317.         if (pTempOpenNode->pNextNode != nil)
  1318.             pTempOpenNode->pNextNode->pPreviousNode = pTempOpenNode->pPreviousNode;
  1319.  
  1320.         if (pTempOpenNode->pPreviousNode != nil)
  1321.             pTempOpenNode->pPreviousNode->pNextNode = pTempOpenNode->pNextNode;
  1322.         else
  1323.             pWinData->pOpenNodeList = pTempOpenNode->pNextNode;
  1324.             
  1325.         DisposePtr((Ptr) pTempOpenNode);
  1326.         pWinData->numOpenNodes--;
  1327.         CloseFWXNode(targetNodeID);
  1328.     }
  1329.     
  1330.     // Traverse the receive node list to find the receive node record for the nodeID
  1331.     foundNodeID = false;
  1332.     pTempRecvNode = pWinData->pRecvNodeList;
  1333.     while ((pTempRecvNode != nil) && (!foundNodeID))
  1334.     {
  1335.         if (pTempRecvNode->nodeID == targetNodeID)
  1336.         {
  1337.             foundNodeID = true;
  1338.             break;
  1339.         }
  1340.         pTempRecvNode = pTempRecvNode->pNextNode;
  1341.     }
  1342.         
  1343.     if (foundNodeID)
  1344.     {    
  1345.         // remove the node from the list
  1346.         if (pTempRecvNode->pNextNode != nil)
  1347.             pTempRecvNode->pNextNode->pPreviousNode = pTempRecvNode->pPreviousNode;
  1348.             
  1349.         if (pTempRecvNode->pPreviousNode != nil)
  1350.             pTempRecvNode->pPreviousNode->pNextNode = pTempRecvNode->pNextNode;
  1351.         else
  1352.             pWinData->pRecvNodeList = pTempRecvNode->pNextNode;
  1353.         
  1354.         // JKL *** how about canceling timer?
  1355.         if (pTempRecvNode->pReplyTimer != nil)
  1356.         {
  1357.             if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  1358.                 DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  1359.             DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  1360.         }
  1361.         DisposePtr((Ptr) pTempRecvNode);
  1362.         pWinData->numRecvNodes--;
  1363.         
  1364.         if (pWinData->numRecvNodes == 0)
  1365.         {
  1366.             HideWindow(gpFWXAppData->pSenderWindow);
  1367.             DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  1368.             DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  1369.             DisableItem(GetMenuHandle(kViewMenuID), 0);
  1370.             DrawMenuBar();
  1371.         }
  1372.         else
  1373.         {
  1374.             // Force an update
  1375.             GetPort(&curPort);
  1376.             pWindowPort = (GrafPtr) GetWindowPort(gpFWXAppData->pSenderWindow);
  1377.             AdjustNodeIcons(pWinData, &pWindowPort->portRect);
  1378.             AdjustScrollBars(gpFWXAppData->pSenderWindow, false);
  1379.             SetPortWindowPort(pWindowPort);
  1380.             InvalRect(&pWindowPort->portRect);
  1381.             SetPort(curPort);
  1382.         }
  1383.     }
  1384.     return err;
  1385. }
  1386.  
  1387. //////////////////////////////////////////////////////////////////////////////
  1388. //
  1389. //    AdjustNodeIcons
  1390. //
  1391. //    Adjust the placement of the node icons in the window. Traverse the list
  1392. //    of nodes setting the rectangle appropriately.
  1393. //
  1394.  
  1395. void AdjustNodeIcons (
  1396.     WindowDataPtr            pWinData,
  1397.     Rect                    *windRect)
  1398. {
  1399.     RecvNodePtr                pRecvNode;
  1400.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1401.     SInt16                    row, column;
  1402.     SInt16                    index;
  1403.     SInt16                    sWidth, sLoc;
  1404.     
  1405.     pRecvNode = pWinData->pRecvNodeList;
  1406.     for (index = 0; index < pWinData->numRecvNodes; index++)
  1407.     {
  1408.         if (pRecvNode == nil)
  1409.             FWDebugStr("\pNode List screwed up in AdjustNodeIcons");
  1410.             
  1411.         // setup drag rectangle
  1412.         sWidth = StringWidth(pRecvNode->nodeName);
  1413.         if (pWinData->windowView == kLargeIconView)
  1414.         {
  1415.             row = index % kLargeRowCount;
  1416.             column = index / kLargeRowCount;
  1417.             rctLeft = kLargeHFill + (column * kLargeHSize);
  1418.             rctRight = rctLeft + kLargeIconFill;
  1419.             rctTop = kLargeVFill + (row * kLargeVSize);
  1420.             rctBottom = rctTop + kLargeIconFill;
  1421.  
  1422.             sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1423.             sLoc -= ((sWidth / 2) + 2);
  1424.             SetRect(&pRecvNode->recvNodeTextRect,
  1425.                     sLoc,
  1426.                     rctBottom,
  1427.                     sLoc + sWidth + 3,
  1428.                     rctBottom + 13); 
  1429.         }
  1430.         else
  1431.         {
  1432.             row = index % kSmallRowCount;
  1433.             column = index / kSmallRowCount;
  1434.             rctLeft = kSmallHFill + (column * kSmallHSize);
  1435.             rctRight = rctLeft + kSmallIconFill;
  1436.             rctTop = kSmallVFill + (row * kSmallVSize);
  1437.             rctBottom = rctTop + kSmallIconFill;
  1438.  
  1439.             SetRect(&pRecvNode->recvNodeTextRect,
  1440.                     rctRight + 2,
  1441.                     rctBottom - 15,
  1442.                     rctRight + sWidth + 5,
  1443.                     rctBottom - 2); 
  1444.         }    
  1445.         SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom);
  1446.         pRecvNode = (RecvNodePtr) pRecvNode->pNextNode;
  1447.     }
  1448. }
  1449.  
  1450.  
  1451. //////////////////////////////////////////////////////////////////////////////
  1452. //
  1453. //    HandleGetNodeListEvent
  1454. //
  1455. //    Handle the get node list applescript command
  1456. //
  1457.  
  1458. static pascal OSErr HandleGetNodeListEvent (
  1459.     AppleEvent                *pAppleEvent,
  1460.     AppleEvent                *pReplyEvent,
  1461.     SInt32                    refCon)
  1462. {
  1463.     WindowDataPtr    pWinData;
  1464.     RecvNodePtr        pNodeInfo;
  1465.     AEDescList        nodeList;
  1466.        OSErr            err = noErr;
  1467.  
  1468.     err = AECreateList(nil, 0, false, &nodeList);
  1469.     if (err == noErr) {
  1470.     
  1471.         pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1472.         if (pWinData != nil)
  1473.         {
  1474.             pNodeInfo = pWinData->pRecvNodeList;
  1475.             while ((pNodeInfo != nil) && (!err))
  1476.             {
  1477.                 err = AEPutPtr(&nodeList, 0, typeChar, pNodeInfo->nodeName + 1, pNodeInfo->nodeName[0]);
  1478.                 pNodeInfo = pNodeInfo->pNextNode;
  1479.             }
  1480.             if (err == noErr)
  1481.                 err = AEPutKeyDesc(pReplyEvent, keyDirectObject, &nodeList);
  1482.         }
  1483.     }
  1484.     
  1485.     return  err;
  1486. }
  1487.  
  1488. //////////////////////////////////////////////////////////////////////////////
  1489. //
  1490. //    HandleSendItemsEvent
  1491. //
  1492. //    Handle the send applescript command
  1493. //
  1494. static pascal OSErr HandleSendItemsEvent (
  1495.     AppleEvent                *pAppleEvent,
  1496.     AppleEvent                *pReplyEvent,
  1497.     SInt32                    refCon)
  1498. {
  1499.     FWXNodeID                *pNodeIDList = nil;
  1500.     FSSpecPtr                pFileSpecList = nil;
  1501.     AESendRecPtr            pAESendElem;
  1502.     UInt16                    numFSItems;
  1503.     UInt16                    numNodes;
  1504.     UInt16                    index;
  1505.     OSErr                    err;
  1506.     
  1507.     // get items to be sent from event
  1508.     err = GetFSItemsFromEvent(&pFileSpecList, pAppleEvent, &numFSItems);
  1509.  
  1510.     // get the list of receive targets from event
  1511.     if (err == noErr)
  1512.         err = GetReceiveNodesFromEvent(&pNodeIDList, pAppleEvent, &numNodes);
  1513.         
  1514.     if (err == noErr)
  1515.     {
  1516.         for (index = 0; index < numNodes; index++)
  1517.         {
  1518.             pAESendElem = (AESendRecPtr) NewPtr(sizeof(AESendRec));
  1519.             if (pAESendElem == nil)
  1520.             {
  1521.                 err = memFullErr;
  1522.                 break;
  1523.             }
  1524.             else
  1525.             {
  1526.                 pAESendElem->pSendItemsList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numFSItems);
  1527.                 if (pAESendElem->pSendItemsList != nil)
  1528.                 {
  1529.                     BlockMove(pFileSpecList, pAESendElem->pSendItemsList, sizeof(FSSpec) * numFSItems);
  1530.                     pAESendElem->recvNode = pNodeIDList[index];
  1531.                     pAESendElem->numSendItems = numFSItems;
  1532.                     Enqueue((QElemPtr) pAESendElem, &gAESendQHdr);
  1533.                 }
  1534.                 else
  1535.                 {
  1536.                     err = memFullErr;
  1537.                     break;
  1538.                 }
  1539.             }
  1540.         }
  1541.     }
  1542.     
  1543.     if (pNodeIDList != nil)
  1544.         DisposePtr((Ptr) pNodeIDList);
  1545.     if (pFileSpecList != nil)
  1546.         DisposePtr((Ptr) pFileSpecList);
  1547.         
  1548.     if (!(gSendingFile || gCheckingTransfer))
  1549.     {
  1550.         pAESendElem = (AESendRecPtr) gAESendQHdr.qHead;
  1551.         if (pAESendElem != nil)
  1552.         {
  1553.             Dequeue((QElemPtr) pAESendElem, &gAESendQHdr);
  1554.             SendFSSpecListToSelf(pAESendElem->recvNode, pAESendElem->pSendItemsList, pAESendElem->numSendItems);
  1555.             DisposePtr((Ptr) pAESendElem->pSendItemsList);
  1556.             DisposePtr((Ptr) pAESendElem);
  1557.         }
  1558.     }
  1559.     
  1560.     err = AEPutKeyPtr(pReplyEvent, keyDirectObject, typeShortInteger, &err, sizeof(OSErr));
  1561.     return err;
  1562. }
  1563.  
  1564. //////////////////////////////////////////////////////////////////////////////
  1565. //
  1566. //    GetReceiveNodesFromEvent
  1567. //
  1568. //    Get the target nodes for the transfer out of the event
  1569. //
  1570. static OSErr GetReceiveNodesFromEvent (
  1571.     FWXNodeID                **pReceiveNodeIDList,
  1572.     AppleEvent                *pAppleEvent,
  1573.     UInt16                    *numNodes)
  1574. {    
  1575.     Ptr                        p = nil;
  1576.     AEDescList                descriptorList;
  1577.     SInt32                    itemCount;
  1578.     AEKeyword                keywd;
  1579.     DescType                returnedType;
  1580.     Size                    actualSize;
  1581.     UInt16                    i;
  1582.     OSErr                    err;
  1583.     
  1584.     err = AEGetParamDesc(pAppleEvent, kAEFWXNodeKeyword, typeAEList, &descriptorList);
  1585.     if (err == noErr)
  1586.     {
  1587.         err = AECountItems(&descriptorList, &itemCount);
  1588.         if (err == noErr)
  1589.         {
  1590.             *numNodes = itemCount;
  1591.             *pReceiveNodeIDList = (FWXNodeID *) NewPtr(sizeof(FWXNodeID) * itemCount);
  1592.             if (*pReceiveNodeIDList == nil)
  1593.                 err = memFullErr;
  1594.         }
  1595.     
  1596.         if (err == noErr)
  1597.         {
  1598.             for (i = 1; i <= itemCount; i++)
  1599.             {
  1600.                 err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1601.                                     p, 0, &actualSize);
  1602.                 if (err == noErr)
  1603.                 {
  1604.                     p = NewPtr(actualSize + 1);
  1605.                     if (p == nil)
  1606.                     {
  1607.                         err = memFullErr;
  1608.                         break;
  1609.                     }
  1610.                     
  1611.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1612.                                     p + 1, actualSize, &actualSize);
  1613.                     p[0] = actualSize;
  1614.                     err = GetNodeIDFromName(&((*pReceiveNodeIDList)[i-1]), (ConstStr255Param) p);
  1615.                     DisposePtr(p);
  1616.                     if (err != noErr)
  1617.                         break;
  1618.                 }
  1619.             }
  1620.         }
  1621.         AEDisposeDesc(&descriptorList);
  1622.     }
  1623.     return err;
  1624. }
  1625.  
  1626. //////////////////////////////////////////////////////////////////////////////
  1627. //
  1628. //    GetNodeIDFromName
  1629. //
  1630. //    Get the node id from the node name.
  1631. //
  1632. static OSErr GetNodeIDFromName (
  1633.     FWXNodeID                *nodeID,
  1634.     ConstStr255Param        nodeName)
  1635. {
  1636.     WindowDataPtr            pWinData;
  1637.     RecvNodePtr                pRecvNode;
  1638.     OSErr                    err = noErr;
  1639.     
  1640.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1641.     if (pWinData == nil)
  1642.         return memFullErr;
  1643.         
  1644.     *nodeID = kInvalidFWXNodeID;
  1645.     pRecvNode = pWinData->pRecvNodeList;
  1646.     while (pRecvNode != nil)
  1647.     {
  1648.         if (EqualString(nodeName, pRecvNode->nodeName, false, false))
  1649.             break;
  1650.         pRecvNode = pRecvNode->pNextNode;
  1651.     }
  1652.  
  1653.     if (pRecvNode == nil)
  1654.         err = qErr;        // nodeName not found
  1655.     else
  1656.         *nodeID = pRecvNode->nodeID;
  1657.  
  1658.     return err;
  1659. }
  1660.  
  1661.  
  1662. //////////////////////////////////////////////////////////////////////////////
  1663. //
  1664. //    GetFSItemsFromEvent
  1665. //
  1666. //    Get the list of items to be sent out of the appleevent.
  1667. //
  1668. static OSErr GetFSItemsFromEvent (
  1669.     FSSpecPtr                *pSendItems,
  1670.     AppleEvent                *pEvent,
  1671.     UInt16                    *numItems)
  1672. {    
  1673.     Ptr                        p;
  1674.     FSSpecPtr                pFileList;
  1675.     AEDescList                descriptorList;
  1676.     AEKeyword                keywd;
  1677.     DescType                returnedType;
  1678.     Size                    actualSize;
  1679.     SInt32                    itemCount;
  1680.     SInt32                    i;
  1681.     OSErr                    err;
  1682.  
  1683.     err = AEGetParamDesc(pEvent, keyDirectObject, typeAEList, &descriptorList);
  1684.     if (err == noErr)
  1685.     {
  1686.         err = AECountItems(&descriptorList, &itemCount);
  1687.         pFileList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * itemCount);
  1688.         if (pFileList == nil)
  1689.             err = memFullErr;
  1690.         
  1691.         if (err == noErr)
  1692.         {
  1693.             for (i = 1; i <= itemCount; i++)
  1694.             {
  1695.                 err = AEGetNthPtr(&descriptorList, i, typeFSS, &keywd, &returnedType,
  1696.                                     &pFileList[i-1], sizeof(FSSpec), &actualSize);
  1697.                 if (err == errAECoercionFail)
  1698.                 {
  1699.                     // try getting the data out as string and rolling our own fsspec
  1700.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1701.                                         p, 0, &actualSize);
  1702.                     if (err == noErr)
  1703.                     {
  1704.                         p = NewPtr(actualSize + 1);
  1705.                         if (p != nil)
  1706.                         {
  1707.                             err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1708.                                                 p + 1, actualSize, &actualSize);
  1709.                             if (err == noErr)
  1710.                             {
  1711.                                 p[0] = actualSize;
  1712.                                 err = FSMakeFSSpec(0, 0, (ConstStr255Param) p, &pFileList[i-1]);
  1713.                             }
  1714.                             DisposePtr(p);
  1715.                         }
  1716.                         else
  1717.                         {
  1718.                             err = errAECoercionFail;
  1719.                             break;
  1720.                         }
  1721.                     }
  1722.                 } 
  1723.             }
  1724.         }
  1725.         AEDisposeDesc(&descriptorList);
  1726.         *numItems = itemCount;
  1727.         *pSendItems = pFileList;
  1728.     }
  1729.     return err;
  1730. }
  1731.  
  1732.  
  1733. //////////////////////////////////////////////////////////////////////////////
  1734. //
  1735. //    HandleOpenApplicationEvent
  1736. //
  1737. //    Do nothing for now
  1738. //
  1739.  
  1740. static pascal OSErr HandleOpenApplicationEvent (
  1741.     AppleEvent                *pAppleEvent,
  1742.     AppleEvent                *pReplyEvent,
  1743.     SInt32                    refCon)
  1744. {
  1745.     return noErr;
  1746. }
  1747.  
  1748. //////////////////////////////////////////////////////////////////////////////
  1749. //
  1750. //    HandleOpenDocumentsEvent
  1751. //
  1752. //    Do nothing for now, eventually send a list of items
  1753. //
  1754.  
  1755. static pascal OSErr HandleOpenDocumentsEvent (
  1756.     AppleEvent                *pAppleEvent,
  1757.     AppleEvent                *pReplyEvent,
  1758.     SInt32                    refCon)
  1759. {
  1760.     return noErr;
  1761. }
  1762.  
  1763. //////////////////////////////////////////////////////////////////////////////
  1764. //
  1765. //    HandleQuitApplicationEvent
  1766. //
  1767. //    quit the app
  1768. //
  1769.  
  1770. static pascal OSErr HandleQuitApplicationEvent (
  1771.     AppleEvent                *pAppleEvent,
  1772.     AppleEvent                *pReplyEvent,
  1773.     SInt32                    refCon)
  1774. {
  1775.  
  1776.     HandleQuit();     // set the quit flag (doesn't immediately quit)
  1777.     return noErr;
  1778. }
  1779.  
  1780.  
  1781. //////////////////////////////////////////////////////////////////////////////
  1782. //
  1783. // InstallAppleEventHandlers
  1784. //
  1785. // Setup handlers for standard open app, open documents, quit app
  1786. // Also handler for when a user drops files on a FireWire Exchange node.
  1787. //
  1788.  
  1789. static OSErr InstallAppleEventHandlers (void)
  1790. {
  1791.     OSErr err = noErr;
  1792.     
  1793.     // Create open application event handler.
  1794.     gpFWXAppData->openApplicationEventHandler =
  1795.         NewAEEventHandlerProc (HandleOpenApplicationEvent);
  1796.     if (gpFWXAppData->openApplicationEventHandler == nil)
  1797.         err = memFullErr;
  1798.  
  1799.     // Install handler.
  1800.     if (err == noErr) {
  1801.         err = AEInstallEventHandler
  1802.                 (kCoreEventClass,
  1803.                  kAEOpenApplication,
  1804.                  gpFWXAppData->openApplicationEventHandler,
  1805.                  (SInt32) gpFWXAppData,
  1806.                  false);
  1807.         if (err == noErr) {
  1808.             gpFWXAppData->openApplicationEventHandlerInstalled =
  1809.                 true;
  1810.         }
  1811.     }
  1812.  
  1813.     if (err == noErr) {
  1814.         // Create open documents event handler.
  1815.         gpFWXAppData->openDocumentsEventHandler =
  1816.             NewAEEventHandlerProc (HandleOpenDocumentsEvent);
  1817.         if (gpFWXAppData->openDocumentsEventHandler == nil)
  1818.             err = memFullErr;
  1819.     
  1820.         // Install handler.
  1821.         if (err == noErr) {
  1822.             err = AEInstallEventHandler
  1823.                     (kCoreEventClass,
  1824.                      kAEOpenDocuments,
  1825.                      gpFWXAppData->openDocumentsEventHandler,
  1826.                      (SInt32) gpFWXAppData,
  1827.                      false);
  1828.             if (err == noErr) {
  1829.                 gpFWXAppData->openDocumentsEventHandlerInstalled =
  1830.                     true;
  1831.             }
  1832.         }
  1833.     }
  1834.  
  1835.     if (err == noErr) {
  1836.         // Create quit application event handler.
  1837.         gpFWXAppData->quitApplicationEventHandler =
  1838.             NewAEEventHandlerProc (HandleQuitApplicationEvent);
  1839.         if (gpFWXAppData->quitApplicationEventHandler == nil)
  1840.             err = memFullErr;
  1841.     
  1842.         // Install handler.
  1843.         if (err == noErr) {
  1844.             err = AEInstallEventHandler
  1845.                     (kCoreEventClass,
  1846.                      kAEQuitApplication,
  1847.                      gpFWXAppData->quitApplicationEventHandler,
  1848.                      (SInt32) gpFWXAppData,
  1849.                      false);
  1850.             if (err == noErr) {
  1851.                 gpFWXAppData->quitApplicationEventHandlerInstalled =
  1852.                     true;
  1853.             }
  1854.         }
  1855.     }
  1856.  
  1857.     if (err == noErr) {
  1858.         // Create fsspec list handler.
  1859.         gpFWXAppData->fileSpecListHandler =
  1860.             NewAEEventHandlerProc (HandleAEFileSpecList);
  1861.         if (gpFWXAppData->fileSpecListHandler == nil)
  1862.             err = memFullErr;
  1863.     
  1864.         // Install handler.
  1865.         if (err == noErr) {
  1866.             err = AEInstallEventHandler
  1867.                     (kAEFWXEventClass,
  1868.                      kAEFileSpecList,
  1869.                      gpFWXAppData->fileSpecListHandler,
  1870.                      (SInt32) gpFWXAppData,
  1871.                      false);
  1872.             if (err == noErr) {
  1873.                 gpFWXAppData->fileSpecListHandlerInstalled =
  1874.                     true;
  1875.             }
  1876.         }
  1877.     }
  1878.     
  1879.     // Create device added event handler.
  1880.     if (err == noErr) {
  1881.         gpFWXAppData->deviceAddedEventHandler =
  1882.             NewAEEventHandlerProc (HandleDeviceAddedEvent);
  1883.         if (gpFWXAppData->deviceAddedEventHandler == nil)
  1884.             err = memFullErr;
  1885.     }
  1886.  
  1887.     // Install handler.
  1888.     if (err == noErr) {
  1889.         err = AEInstallEventHandler
  1890.                 (kAEFWXEventClass,
  1891.                  kAEFWXDeviceAdded,
  1892.                  gpFWXAppData->deviceAddedEventHandler,
  1893.                  (SInt32) gpFWXAppData,
  1894.                  false);
  1895.         if (err == noErr) {
  1896.             gpFWXAppData->deviceAddedEventHandlerInstalled =
  1897.                 true;
  1898.         }
  1899.     }
  1900.  
  1901.     // Create device removed event handler.
  1902.     if (err == noErr)
  1903.     {
  1904.         gpFWXAppData->deviceRemovedEventHandler =
  1905.             NewAEEventHandlerProc (HandleDeviceRemovedEvent);
  1906.         if (gpFWXAppData->deviceRemovedEventHandler == nil)
  1907.             err = memFullErr;
  1908.     }
  1909.  
  1910.     // Install handler.
  1911.     if (err == noErr)
  1912.     {
  1913.         err = AEInstallEventHandler
  1914.                 (kAEFWXEventClass,
  1915.                  kAEFWXDeviceRemoved,
  1916.                  gpFWXAppData->deviceRemovedEventHandler,
  1917.                  (SInt32) gpFWXAppData,
  1918.                  false);
  1919.         if (err == noErr)
  1920.         {
  1921.             gpFWXAppData->deviceRemovedEventHandlerInstalled =
  1922.                 true;
  1923.         }
  1924.     }
  1925.  
  1926.     // Create device send items event handler.
  1927.     if (err == noErr)
  1928.     {
  1929.         gpFWXAppData->sendItemsEventHandler =
  1930.             NewAEEventHandlerProc (HandleSendItemsEvent);
  1931.         if (gpFWXAppData->sendItemsEventHandler == nil)
  1932.             err = memFullErr;
  1933.     }
  1934.  
  1935.     // Install handler.
  1936.     if (err == noErr)
  1937.     {
  1938.         err = AEInstallEventHandler
  1939.                 (kAEFWXEventClass,
  1940.                  kAEFWXSendEventID,
  1941.                  gpFWXAppData->sendItemsEventHandler,
  1942.                  (SInt32) gpFWXAppData,
  1943.                  false);
  1944.         if (err == noErr)
  1945.         {
  1946.             gpFWXAppData->sendItemsEventHandlerInstalled =
  1947.                 true;
  1948.         }
  1949.     }
  1950.  
  1951.     // Create get node list event handler.
  1952.     if (err == noErr)
  1953.     {
  1954.         gpFWXAppData->getNodeListEventHandler =
  1955.             NewAEEventHandlerProc (HandleGetNodeListEvent);
  1956.         if (gpFWXAppData->getNodeListEventHandler == nil)
  1957.             err = memFullErr;
  1958.     }
  1959.  
  1960.     // Install handler.
  1961.     if (err == noErr)
  1962.     {
  1963.         err = AEInstallEventHandler
  1964.                 (kAEFWXEventClass,
  1965.                  kAEFWXNodeListID,
  1966.                  gpFWXAppData->getNodeListEventHandler,
  1967.                  (SInt32) gpFWXAppData,
  1968.                  false);
  1969.         if (err == noErr)
  1970.         {
  1971.             gpFWXAppData->getNodeListEventHandlerInstalled =
  1972.                 true;
  1973.         }
  1974.     }
  1975.     return err;
  1976. }
  1977.  
  1978.  
  1979. //////////////////////////////////////////////////////////////////////////////
  1980. //
  1981. // InstallCompletionRoutineProcs
  1982. //
  1983. // Setup handlers for our file read/write async completion procs
  1984. //    and FireWire read/write async completion procs
  1985. //
  1986.  
  1987. enum {
  1988.     uppIOCompletionProcWorkaroundInfo =
  1989.         kRegisterBased |
  1990.         RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
  1991.         REGISTER_RESULT_LOCATION(kRegisterD0) |
  1992.         REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(ParmBlkPtr)))
  1993. };
  1994.  
  1995. #define NewIOCompletionProcWorkaround(userRoutine)        \
  1996.         (IOCompletionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine),    \
  1997.                                                uppIOCompletionProcWorkaroundInfo,    \
  1998.                                                GetCurrentArchitecture())
  1999.  
  2000. static OSErr InstallCompletionRoutineProcs (void)
  2001. {
  2002.     OSErr err = noErr;
  2003.     
  2004.     gpFWXAppData->fileReadCompletionHandler =
  2005.         NewIOCompletionProcWorkaround(HandleFileReadComplete);
  2006.  
  2007.     if (gpFWXAppData->fileReadCompletionHandler == nil)
  2008.         err = memFullErr;
  2009.     else
  2010.         HoldMemory(gpFWXAppData->fileReadCompletionHandler, 32*1024);    // JKL some large amount
  2011.  
  2012.     if (err == noErr) {
  2013.         gpFWXAppData->fileWriteCompletionHandler =
  2014.             NewIOCompletionProcWorkaround(HandleFileWriteComplete);
  2015.     
  2016.         if (gpFWXAppData->fileWriteCompletionHandler == nil)
  2017.             err = memFullErr;
  2018.         else
  2019.             HoldMemory(gpFWXAppData->fileWriteCompletionHandler, 32*1024);    // JKL some large amount
  2020.     
  2021.         // while here go ahead and hold some other interrupt level stuff
  2022.         HoldMemory(HandleFWWriteComplete, 32*1024);
  2023.         HoldMemory(HandleFWReadComplete, 32*1024);
  2024.         HoldMemory(HandleFWControlComplete, 32*1024);
  2025.         HoldMemory(FWIXDequeue, 32*1024);
  2026.         HoldMemory(SetupFileReadPB, 32*1024);
  2027.         HoldMemory(&gFileReadQHdr, 32*1024);
  2028.         HoldMemory(&gFWControlQHdr, 32*1024);
  2029.         HoldMemory(&gReceiveQHdr, 32*1024);
  2030.     }
  2031.  
  2032.     return err;
  2033.  
  2034. }
  2035.  
  2036. ////////////////////////////////////////////////////////////////////////////////
  2037. //
  2038. // DrawWindow
  2039. //
  2040. //    Draws the space areas in the window
  2041. //
  2042. static void DrawWindow (
  2043.     WindowPtr            pWin)
  2044. {
  2045.     Handle                hIconSuite;
  2046.     RgnHandle            hOldClip;
  2047.     WindowDataPtr        pWinData;
  2048.     StringPtr            pString;
  2049.     Rect                iconRect, textRect;
  2050.     Rect                drawRect;
  2051.     SInt16                nodeIndex;
  2052.     OSErr                err;
  2053.     
  2054.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2055.     if (pWinData != nil)
  2056.     {
  2057.         GetClip(hOldClip = NewRgn());
  2058.         EraseRect(&pWin->portRect);
  2059.         DrawControls(pWin);
  2060.         DrawGrowIcon(pWin);
  2061.     
  2062.         SetOrigin (GetControlValue(pWinData->hHScrollBar),
  2063.                    GetControlValue(pWinData->hVScrollBar));
  2064.         drawRect = pWin->portRect;
  2065.         drawRect.bottom -= kScrollBarAdjust;
  2066.         drawRect.right -= kScrollBarAdjust;
  2067.         ClipRect(&drawRect);
  2068.         
  2069.         err = GetIconSuite(&hIconSuite, kDropIconSuiteID, svAllAvailableData);
  2070.         for (nodeIndex = 1; nodeIndex <= pWinData->numRecvNodes; nodeIndex ++)
  2071.         {
  2072.             GetNodeDragRect(pWin, nodeIndex, &iconRect, &textRect);
  2073.             GetNodeName(pWin, nodeIndex, &pString);
  2074.             PlotIconSuite(&iconRect, atNone, ttNone, hIconSuite);
  2075.             InsetRect(&textRect, 1, 0);
  2076.             TETextBox(pString + 1, pString[0], &textRect, teJustLeft);
  2077.         }
  2078.         DisposeIconSuite(hIconSuite, false);
  2079.         SetOrigin(0, 0);
  2080.         SetClip(hOldClip);
  2081.         DisposeRgn(hOldClip);
  2082.     }
  2083. }
  2084.  
  2085. ////////////////////////////////////////////////////////////////////////////////
  2086. //
  2087. //    CreateMenus
  2088. //
  2089. //    Make our menu bar. We only do about, open, and quit.
  2090. //
  2091.  
  2092. static OSErr CreateMenus()
  2093. {
  2094.     OSErr        err = noErr;
  2095.     Handle        hMenuBarResource;
  2096.     
  2097.     hMenuBarResource = GetNewMBar (kMenuBarResourceID);
  2098.     if (hMenuBarResource != nil)
  2099.     {
  2100.         SetMenuBar (hMenuBarResource);
  2101.         DisposeHandle (hMenuBarResource);
  2102.         AppendResMenu (GetMenuHandle (kAppleMenuID), 'DRVR');
  2103.         DrawMenuBar ();
  2104.     } else
  2105.         err = resNotFound;
  2106.  
  2107.     return err;
  2108. }
  2109.  
  2110.  
  2111. ////////////////////////////////////////////////////////////////////////////////
  2112. //
  2113. //    HandleCloseWindow
  2114. //
  2115. //    Disposes of a window and its refcon memory.
  2116. //
  2117.  
  2118. static void HandleCloseWindow (
  2119.     WindowPtr        pWin)
  2120. {
  2121.     WindowDataPtr    pWinData;
  2122.     OpenNodePtr        pTempOpenNode;
  2123.     RecvNodePtr        pTempRecvNode;
  2124.     
  2125.     if (pWin != nil) {
  2126.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2127.         if (pWinData != nil) {
  2128.         
  2129.             // dispose of the receive node records
  2130.             pTempRecvNode = pWinData->pRecvNodeList;
  2131.             while (pTempRecvNode != nil)
  2132.             {
  2133.                 if (pTempRecvNode->pReplyTimer != nil)
  2134.                 {
  2135.                     if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  2136.                         DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  2137.                     DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  2138.                 }
  2139.                     
  2140.                 pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  2141.                 DisposePtr((Ptr) pWinData->pRecvNodeList);
  2142.                 pWinData->pRecvNodeList = pTempRecvNode;
  2143.             }
  2144.             
  2145.             // dispose of the open node records
  2146.             pTempOpenNode = pWinData->pOpenNodeList;
  2147.             while (pTempOpenNode != nil)
  2148.             {
  2149.                 CloseFWXNode(pTempOpenNode->nodeID);
  2150.                 
  2151.                 pTempOpenNode = (OpenNodePtr) pTempOpenNode->pNextNode;
  2152.                 DisposePtr((Ptr) pWinData->pOpenNodeList);
  2153.                 pWinData->pOpenNodeList = pTempOpenNode;
  2154.             }
  2155.             
  2156.             DisposePtr((Ptr) pWinData);
  2157.             DisposeWindow(pWin);
  2158.         }
  2159.     }
  2160. }
  2161.  
  2162. //////////////////////////////////////////////////////////////////////////////
  2163. //
  2164. //    HandleQuit
  2165. //
  2166. //    Quit the app
  2167. //
  2168.  
  2169. static void HandleQuit (void)
  2170. {
  2171.     SInt16            itemHit;
  2172.     
  2173.     if (gSendingFile || gCheckingTransfer) {
  2174.         // JKL *** does ok button work right? Complete and then quit
  2175.         // is background processing correct?
  2176.         itemHit = HandleCautionAlert(kCantQuitAlertID);
  2177.         if (itemHit == kCancelButton) {        // the abort and quit button
  2178.             StopTransfer(nil);
  2179.             gpFWXAppData->quitFlag = true;
  2180.         }
  2181.     } else {
  2182.         gpFWXAppData->quitFlag = true;
  2183.     }
  2184.     
  2185.     if (gpFWXAppData->quitFlag) {
  2186.         SendFWXQuit();
  2187.         if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2188.             NMRemove(gpFWXAppData->pNotifyRec);
  2189.             
  2190.         if (gpFWXAppData->pSenderWindow != nil)
  2191.             HandleCloseWindow(gpFWXAppData->pSenderWindow);
  2192.         RemoveDragHandlers();
  2193.     }
  2194.  
  2195. }
  2196.  
  2197.  
  2198. //////////////////////////////////////////////////////////////////////////////
  2199. //
  2200. //    HandleMenuCommand
  2201. //
  2202. //    handle repsonses to user menu selections
  2203. //
  2204.  
  2205. static void HandleMenuCommand(
  2206.     SInt32                    menuCommand)
  2207. {
  2208.     VersRecHndl                h;
  2209.     WindowPtr                pWin;
  2210.     UInt8                    *vers;
  2211.     SInt16                    menuID;
  2212.     SInt16                    menuItem;
  2213.     Str255                    deskAccessoryName;
  2214.     
  2215.     menuID = menuCommand >> 16;
  2216.     menuItem = menuCommand & 0xFFFF;
  2217.  
  2218.     switch (menuID)
  2219.     {
  2220.         case kAppleMenuID:
  2221.             if (menuItem == kAboutMenuItem)
  2222.             {
  2223.                 h = (VersRecHndl) Get1Resource('vers', 1);
  2224.                 vers = (**h).shortVersion;
  2225.                 vers += (vers[0] + 1);
  2226.                 ParamText(vers, "\p", "\p", "\p");
  2227.                 HandleAlert(kAboutAlertResourceID);
  2228.             }
  2229.             else
  2230.             {
  2231.                 GetMenuItemText(GetMenuHandle(kAppleMenuID), menuItem, deskAccessoryName);
  2232.                 OpenDeskAcc(deskAccessoryName);
  2233.             }
  2234.             break;
  2235.  
  2236.         case kFileMenuID:
  2237.             switch (menuItem)
  2238.             {
  2239.                 case kOpenMenuItem:
  2240.                     pWin = gpFWXAppData->pSenderWindow;
  2241.                     ShowWindow(pWin);
  2242.                     EnableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2243.                     DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2244.                     EnableItem(GetMenuHandle(kViewMenuID), 0);
  2245.                     DrawMenuBar();
  2246.                     break;
  2247.                 case kCloseMenuItem:
  2248.                     pWin = gpFWXAppData->pSenderWindow;
  2249.                     HideWindow(pWin);
  2250.                     EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2251.                     DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2252.                     DisableItem(GetMenuHandle(kViewMenuID), 0);
  2253.                     DrawMenuBar();
  2254.                     break;
  2255.                 case kOpenDropMenuItem:
  2256.                     OpenDropFolder();
  2257.                     break;
  2258.                 case kQuitMenuItem:
  2259.                     HandleQuit();
  2260.                     break;
  2261.             }
  2262.             break;
  2263.         case kEditMenuID:
  2264.             switch (menuItem)
  2265.             {
  2266.                 case kPrefsMenuItem:
  2267.                     HandlePrefsDialog();
  2268.                     break;
  2269.             }
  2270.         case kViewMenuID:
  2271.             switch (menuItem)
  2272.             {
  2273.                 case kSmallIconMenuItem:
  2274.                 case kIconMenuItem:
  2275.                     HandleViewSize(menuItem);
  2276.                     break;
  2277.             }
  2278.             break;
  2279.     }
  2280.     HiliteMenu(0);      // unhilight menu title
  2281. }
  2282.  
  2283. //////////////////////////////////////////////////////////////////////////////
  2284. //
  2285. //    OpenDropFolder
  2286. //
  2287. //    Send an appleevent to the finder to open our drop folder
  2288. //
  2289. OSErr OpenDropFolder(void)
  2290. {
  2291.     AppleEvent                send;
  2292.     AppleEvent                reply;
  2293.     AEDesc                    target;
  2294.     ProcessSerialNumber        psn;
  2295.     ProcessInfoRecPtr        pInfo;
  2296.     SInt32                    dirID;
  2297.     OSErr                    err;
  2298.  
  2299.     psn.highLongOfPSN = kNoProcess;
  2300.     psn.lowLongOfPSN = kNoProcess;
  2301.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2302.     if (pInfo == nil)
  2303.         return memFullErr;
  2304.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2305.     pInfo->processName = nil;
  2306.     pInfo->processAppSpec = nil;
  2307.     do {
  2308.         err = GetNextProcess(&psn);
  2309.         GetProcessInformation(&psn, pInfo);
  2310.     }
  2311.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2312.     DisposePtr((Ptr) pInfo);
  2313.     
  2314.     err = FSpDirCreate(&gpFWXAppData->fwixReceiveFolder, smSystemScript, &dirID);
  2315.     if (err == dupFNErr)
  2316.         err = noErr;
  2317.         
  2318.     if (err == noErr) {
  2319.                 
  2320.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2321.         if (err != noErr)
  2322.             return err;
  2323.  
  2324.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2325.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2326.         
  2327.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &(gpFWXAppData->fwixReceiveFolder), sizeof(FSSpec));
  2328.  
  2329.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2330.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2331.  
  2332.         AEDisposeDesc(&target);
  2333.         AEDisposeDesc(&send);
  2334.     }
  2335.     SetFrontProcess(&psn);
  2336.     
  2337.     return err;
  2338. }
  2339.  
  2340. //////////////////////////////////////////////////////////////////////////////
  2341. //
  2342. //    OpenSharingSetup
  2343. //
  2344. //    Send an appleevent to the finder to open the Sharing Setup Control Panel
  2345. //
  2346. static OSErr OpenSharingSetup(void)
  2347. {
  2348.     AppleEvent                send;
  2349.     AppleEvent                reply;
  2350.     AEDesc                    target;
  2351.     ProcessSerialNumber        psn;
  2352.     ProcessInfoRecPtr        pInfo;
  2353.     FSSpec                    spec;
  2354.     SInt32                    dirID;
  2355.     SInt16                    vRefNum;
  2356.     OSErr                    err;
  2357.  
  2358.     psn.highLongOfPSN = kNoProcess;
  2359.     psn.lowLongOfPSN = kNoProcess;
  2360.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2361.     if (pInfo == nil)
  2362.         return memFullErr;
  2363.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2364.     pInfo->processName = nil;
  2365.     pInfo->processAppSpec = nil;
  2366.     do {
  2367.         err = GetNextProcess(&psn);
  2368.         GetProcessInformation(&psn, pInfo);
  2369.     }
  2370.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2371.     DisposePtr((Ptr) pInfo);
  2372.     
  2373.     if (err == noErr) {
  2374.                 
  2375.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2376.         if (err != noErr)
  2377.             return err;
  2378.  
  2379.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2380.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2381.         
  2382.         err = FindFolder(kOnSystemDisk, kControlPanelFolderType, kDontCreateFolder,
  2383.                         &vRefNum, &dirID);
  2384.         err = FSMakeFSSpec(vRefNum, dirID, "\pSharing Setup", &spec);
  2385.         if (err == fnfErr)
  2386.             err = FSMakeFSSpec(vRefNum, dirID, "\pFile Sharing", &spec);
  2387.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &spec, sizeof(FSSpec));
  2388.  
  2389.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2390.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2391.  
  2392.         AEDisposeDesc(&target);
  2393.         AEDisposeDesc(&send);
  2394.     }
  2395.     SetFrontProcess(&psn);
  2396.     
  2397.     return err;
  2398. }
  2399.  
  2400. ////////////////////////////////////////////////////////////////////////////////
  2401. //
  2402. //    HandleViewSize
  2403. //
  2404. //    Handle the window view size command.
  2405. //
  2406. static OSErr HandleViewSize(
  2407.     SInt16                    whichMenuItem)
  2408. {
  2409.     MenuHandle                hMenu;
  2410.     WindowPtr                pWin;
  2411.     WindowDataPtr            pWinData;
  2412.     OSErr                    err = noErr;
  2413.     
  2414.     pWin = gpFWXAppData->pSenderWindow;
  2415.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2416.     if (pWinData == nil)
  2417.         return memFullErr;
  2418.     
  2419.     hMenu = GetMenuHandle(kViewMenuID);
  2420.     if ((pWinData->windowView == kLargeIconView) && (whichMenuItem == kSmallIconMenuItem))
  2421.     {
  2422.         pWinData->windowView = kSmallIconView;
  2423.         gpFWXAppData->fwixPrefs |= kIconView;
  2424.         SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  2425.         SetItemMark(hMenu, kIconMenuItem, noMark);
  2426.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2427.         AdjustScrollBars(pWin, false);
  2428.         UpdatePrefsFile();
  2429.     }
  2430.     else if ((pWinData->windowView == kSmallIconView) && (whichMenuItem == kIconMenuItem))
  2431.     {
  2432.         pWinData->windowView = kLargeIconView;
  2433.         gpFWXAppData->fwixPrefs &= ~kIconView;
  2434.         SetItemMark(hMenu, kSmallIconMenuItem, noMark);
  2435.         SetItemMark(hMenu, kIconMenuItem, checkMark);
  2436.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2437.         AdjustScrollBars(pWin, false);
  2438.         UpdatePrefsFile();
  2439.     }
  2440.     InvalRect(&pWin->portRect);
  2441.     return err;    
  2442. }
  2443.  
  2444. ////////////////////////////////////////////////////////////////////////////////
  2445. //
  2446. //    HandleMouseDownEvent
  2447. //
  2448. //    This routine handles mouse down events.
  2449. //
  2450. static void HandleMouseDownEvent(
  2451.     EventRecord                    *pEventRecord)
  2452. {
  2453.     static ControlActionUPP        cupp;
  2454.     GrafPtr                        curPort;
  2455.     WindowRef                    theWindow;
  2456.     Rect                        tempRect;
  2457.     ControlHandle                hControl;
  2458.     Point                        mouse;
  2459.     SInt16                        whichPart;
  2460.     SInt16                        cntlPart;
  2461.     
  2462.     whichPart = FindWindow(pEventRecord->where, &theWindow);
  2463.     
  2464.     switch (whichPart) {
  2465.         case inSysWindow:  // desk accessory window
  2466.             SystemClick(pEventRecord, theWindow);
  2467.             break;
  2468.  
  2469.         case inMenuBar:
  2470.             HandleMenuCommand(MenuSelect(pEventRecord->where));
  2471.             break;
  2472.  
  2473.         case inDrag:
  2474.             tempRect = qd.screenBits.bounds;
  2475.             if (gpFWXAppData->pSenderWindow != FrontWindow())
  2476.             {
  2477.                 // progress bar would be up, it is movable modal
  2478.                 if (theWindow == FrontWindow())
  2479.                     DragWindow(theWindow, pEventRecord->where, &tempRect);
  2480.                 else
  2481.                     SysBeep(0);
  2482.             } else
  2483.                 DragWindow(theWindow, pEventRecord->where, &tempRect);
  2484.             SaveWindowPos(theWindow);
  2485.             break;
  2486.  
  2487.         case inGoAway:
  2488.             if (TrackGoAway(theWindow, pEventRecord->where)) {
  2489.                 HideWindow(theWindow);
  2490.                 EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2491.                 DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2492.                 DisableItem(GetMenuHandle(kViewMenuID), 0);
  2493.                 DrawMenuBar();
  2494.             }
  2495.             break;
  2496.  
  2497.         case inGrow:
  2498.             HandleGrowWindow(theWindow, pEventRecord->where);
  2499.             break;
  2500.             
  2501.         case inZoomIn:
  2502.         case inZoomOut:
  2503.             if (TrackBox(theWindow, pEventRecord->where, whichPart))
  2504.                 HandleZoomWindow(theWindow, whichPart);
  2505.             break;
  2506.  
  2507.         case inContent:
  2508.                     GetPort(&curPort);
  2509.                     SetPort(theWindow);
  2510.                     mouse = pEventRecord->where;
  2511.                     GlobalToLocal(&mouse);
  2512.                     cntlPart = FindControl(mouse, theWindow, &hControl);    
  2513.             if (cntlPart)
  2514.             {
  2515.                 if (gpFWXAppData->pSenderWindow == FrontWindow())
  2516.                 {
  2517.                     // handle user click in one of the sender window scroll bars
  2518.                     if (cntlPart == inThumb)
  2519.                         HandleThumbScroll(hControl, theWindow, mouse);
  2520.                     else
  2521.                     {
  2522.                         if (!cupp)
  2523.                             cupp = NewControlActionProc(HandleScrollAction);
  2524.                         TrackControl(hControl, mouse, cupp);
  2525.                     }
  2526.                 }
  2527.                 else
  2528.                 {    // progress bar is up, make it modal, check for stop button
  2529.                     if (theWindow != FrontWindow())
  2530.                         SysBeep(0);
  2531.                     else
  2532.                     {
  2533.                         if (cntlPart == inButton)
  2534.                         {
  2535.                             if (TrackControl(hControl, mouse, nil))
  2536.                                 StopTransfer(nil);
  2537.                         }
  2538.                     }
  2539.                 }
  2540.             }
  2541.             SetPort(curPort);
  2542.             break;
  2543.     }
  2544. }
  2545.  
  2546. ////////////////////////////////////////////////////////////////////////////////
  2547. //
  2548. //    HandleThumbScroll
  2549. //
  2550. //    Handle scrolling by the thumb button.
  2551. //
  2552. static pascal void HandleThumbScroll (
  2553.     ControlHandle        scrollCtl,
  2554.     WindowPtr            pWin,
  2555.     Point                mouse)
  2556. {
  2557.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2558.     RgnHandle            updateRgn;
  2559.     Rect                drawRect;
  2560.     SInt16                value, h, v;
  2561.     SInt16                cntlPart;
  2562.     
  2563.     value = GetControlValue(scrollCtl);
  2564.     cntlPart = TrackControl(scrollCtl, mouse, nil);
  2565.     if (cntlPart)
  2566.     {
  2567.         value -= GetControlValue(scrollCtl);
  2568.         if (value != 0)
  2569.         {
  2570.             h = v = 0;
  2571.             if (scrollCtl == pWinData->hVScrollBar)
  2572.                 v = value;
  2573.             else
  2574.                 h = value;
  2575.                 
  2576.             drawRect = pWin->portRect;
  2577.             drawRect.bottom -= kScrollBarAdjust;
  2578.             drawRect.right -= kScrollBarAdjust;
  2579.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2580.             InvalRgn(updateRgn);
  2581.             DisposeRgn(updateRgn);
  2582.             BeginUpdate(pWin);
  2583.             DrawWindow(pWin);
  2584.             EndUpdate(pWin);
  2585.         }
  2586.     }
  2587. }
  2588.  
  2589. ////////////////////////////////////////////////////////////////////////////////
  2590. //
  2591. //    HandleScrollAction
  2592. //
  2593. //    Handle scrolling window.
  2594. //
  2595. static pascal void HandleScrollAction (
  2596.     ControlHandle        scrollCtl,
  2597.     SInt16                part)
  2598. {
  2599.     WindowPtr            pWin = gpFWXAppData->pSenderWindow;
  2600.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2601.     RgnHandle            updateRgn;
  2602.     Rect                drawRect;
  2603.     SInt16                delta, value, h, v;
  2604.     SInt16                oldValue, max;
  2605.  
  2606.     if ((pWinData != nil) && part)
  2607.     {
  2608.         switch (part)
  2609.         {
  2610.             case inUpButton:
  2611.             case inDownButton:
  2612.                 delta = 5;
  2613.                 break;
  2614.  
  2615.             case inPageUp:
  2616.             case inPageDown:
  2617.                 if (scrollCtl == pWinData->hHScrollBar)
  2618.                     delta = pWin->portRect.right - pWin->portRect.left - kScrollBarAdjust;
  2619.                 else
  2620.                     delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;                    
  2621.                 break;
  2622.             
  2623.             // handle cases generated by keyboard input
  2624.             case kPageUpKey:
  2625.             case kPageDownKey:
  2626.                 delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;
  2627.                 break;
  2628.             
  2629.             case kHomeKey:
  2630.                 delta = -32000;        // a large enough number to make value = 0
  2631.                 break;
  2632.             
  2633.             case kEndKey:
  2634.                 delta = 32000;        // a large enough number to make value = max
  2635.                 break;
  2636.         }
  2637.  
  2638.         // reverse direction for scrolling up
  2639.         if ((part == inUpButton) || (part == inPageUp) || (part == kPageUpKey))
  2640.             delta = -delta;
  2641.  
  2642.         // pin scroll value at min or max.
  2643.         oldValue = GetControlValue(scrollCtl);
  2644.         value = oldValue + delta;
  2645.         if (value < 0)
  2646.             value = 0;
  2647.         max = GetControlMaximum(scrollCtl);
  2648.         if (value > max)
  2649.             value = max;
  2650.  
  2651.         if (value != oldValue)
  2652.         {
  2653.             drawRect = pWin->portRect;
  2654.             drawRect.bottom -= kScrollBarAdjust;
  2655.             drawRect.right -= kScrollBarAdjust;
  2656.             SetControlValue(scrollCtl, value);
  2657.             h = oldValue - value;
  2658.             v = 0;
  2659.             if (scrollCtl == pWinData->hVScrollBar)
  2660.             {
  2661.                 v = h;
  2662.                 h = 0;
  2663.             }
  2664.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2665.             InvalRgn(updateRgn);
  2666.             DisposeRgn(updateRgn);
  2667.             BeginUpdate(pWin);
  2668.             DrawWindow(pWin);
  2669.             EndUpdate(pWin);
  2670.         }
  2671.     }
  2672. }
  2673.  
  2674. ////////////////////////////////////////////////////////////////////////////////
  2675. //
  2676. //    HandleZoomWindow
  2677. //
  2678. //    Zoom the window.
  2679. //
  2680. static void HandleZoomWindow(
  2681.     WindowPtr            pWin,
  2682.     SInt16                whichZoom)
  2683. {
  2684.     WindowDataPtr        pWinData;
  2685.     Rect                zoomRect;
  2686.     SInt16                vSize, hSize;
  2687.     SInt16                row, column;
  2688.  
  2689.     if (whichZoom == inZoomOut)
  2690.     {
  2691.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2692.         if (pWinData != nil)
  2693.         {
  2694.             if (pWinData->windowView == kLargeIconView)
  2695.             {
  2696.                 row = pWinData->numRecvNodes % kLargeRowCount;
  2697.                 column = pWinData->numRecvNodes / kLargeRowCount;
  2698.                 if (column == 0)
  2699.                     vSize = row * kLargeVSize;
  2700.                 else
  2701.                     vSize = kLargeRowCount * kLargeVSize;
  2702.                 hSize = (column + 1) * kLargeHSize;
  2703.             }
  2704.             else
  2705.             {    
  2706.                 row = pWinData->numRecvNodes % kSmallRowCount;
  2707.                 column = pWinData->numRecvNodes / kSmallRowCount;
  2708.                 if (column == 0)
  2709.                     vSize = row * kSmallVSize;
  2710.                 else
  2711.                     vSize = kSmallRowCount * kSmallVSize;
  2712.                 // make sure there is enough room for scroll bars
  2713.                 if (vSize < kLargeVSize)
  2714.                     vSize = kLargeVSize;
  2715.                 hSize = (column + 1) * kSmallHSize;
  2716.             }
  2717.         }
  2718.         zoomRect = (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).userState;
  2719.         zoomRect.bottom = zoomRect.top + vSize + kScrollBarWidth;
  2720.         zoomRect.right = zoomRect.left + hSize + kScrollBarWidth;
  2721.         (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).stdState = zoomRect;
  2722.     }
  2723.     ZoomWindow(pWin, whichZoom, FrontWindow() == pWin);
  2724.     AdjustScrollBars(pWin, true);
  2725.     InvalRect(&pWin->portRect);
  2726.     SaveWindowPos(pWin);
  2727. }
  2728.  
  2729. ////////////////////////////////////////////////////////////////////////////////
  2730. //
  2731. //    HandleGrowWindow
  2732. //
  2733. //    Grow the window.
  2734. //
  2735. static void HandleGrowWindow(
  2736.     WindowPtr            pWin,
  2737.     Point                clickLoc)
  2738. {
  2739.     Rect                limitRect;
  2740.     SInt32                growSize;
  2741.     
  2742.     SetRect(&limitRect, kLargeVSize, kLargeVSize, 3000, 3000);
  2743.     growSize = GrowWindow(pWin, clickLoc, &limitRect);
  2744.     if (growSize != 0)
  2745.     {
  2746.         SizeWindow(pWin, LoWord(growSize), HiWord(growSize), true);
  2747.         AdjustScrollBars(pWin, true);
  2748.         InvalRect(&pWin->portRect);
  2749.         SaveWindowPos(pWin);
  2750.     }
  2751. }
  2752.  
  2753. ////////////////////////////////////////////////////////////////////////////////
  2754. //
  2755. //    StopTransfer
  2756. //
  2757. //    Handle user stopping file transfer.
  2758. //
  2759. void StopTransfer (
  2760.     RecvNodePtr                    pNode)
  2761. {
  2762.     FWXPacketPtr                pPktInfo;        // puts a packet structure on ioBuffer
  2763.     IOParamPtr                    pIOPb;            // write parameter block
  2764.     TxFSSpecPtr                    pTxItem;
  2765.     NodeSendItemPtr                pSendItem, pTempItem;
  2766.     
  2767.     if (pNode != nil)
  2768.     {
  2769.         if (pNode->pTxItemList != nil)
  2770.         {
  2771.             pSendItem = pNode->pTxItemList;
  2772.             while (pSendItem != nil)
  2773.             {
  2774.                 pTempItem = pSendItem;
  2775.                 pSendItem = pSendItem->pNextSendItem;
  2776.                 DisposePtr((Ptr) pTempItem);
  2777.             }
  2778.             pNode->pTxItemList = nil;
  2779.         }
  2780.     }
  2781.             
  2782.     if (gSendingFile || gCheckingTransfer)
  2783.     {
  2784.         gCheckingTransfer = false;
  2785.     gForkComplete = true;
  2786.     gForkWriteComplete = true;
  2787.     CleanupCopyDialog(FrontWindow());
  2788.     if (gSendingDataFork || gSendingResFork)
  2789.     {
  2790.         gSendingDataFork = false;
  2791.         gSendingResFork = false;
  2792.         FSClose(gCurForkRefNum);
  2793.     }
  2794.     
  2795.         if (gSendingFile)
  2796.         {
  2797.             gSendingFile = false;
  2798.             
  2799.     // send file stopped to receiver
  2800.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  2801.     if (pIOPb != nil)
  2802.     {
  2803.         SetupFWControlPB(pIOPb);
  2804.                 
  2805.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  2806.         pPktInfo->packetType = kTransferStopped;
  2807.         pIOPb->ioMisc = (Ptr) kTransferStopped;
  2808.         pIOPb->ioReqCount = 4;                // just packet header
  2809.  
  2810.         CallFWXNode(pIOPb);
  2811.     }
  2812.     }
  2813.     }
  2814.  
  2815.     // dequeue and dispose of all file queue entries
  2816.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2817.     while (pTxItem != nil)
  2818.     {
  2819.         Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  2820.         DisposePtr((Ptr) pTxItem->pFSSpec);
  2821.         DisposePtr((Ptr) pTxItem);
  2822.  
  2823.         // get another queue item
  2824.         pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2825.     }
  2826. }
  2827.  
  2828. ////////////////////////////////////////////////////////////////////////////////
  2829. //
  2830. //    HandleUpdateEvent
  2831. //
  2832. //    This routine handles update events.
  2833. //
  2834. void HandleUpdateEvent (
  2835.     EventRecord            *pEventRecord)
  2836. {
  2837.     WindowPtr            pWin;
  2838.     GrafPtr                curPort;
  2839.  
  2840.     pWin = (WindowPtr) pEventRecord->message;
  2841.  
  2842.     GetPort(&curPort);
  2843.     SetPort(pWin);
  2844.     if (pWin == gpFWXAppData->pSenderWindow)
  2845.     {
  2846.         BeginUpdate(pWin);        
  2847.             DrawWindow(pWin);
  2848.         EndUpdate(pWin);
  2849.     }
  2850.     else
  2851.     {
  2852.         BeginUpdate(pWin);
  2853.         UpdateDialog(pWin, pWin->visRgn);
  2854.         EndUpdate(pWin);
  2855.     }
  2856.     SetPort(curPort);
  2857. }
  2858.  
  2859. ////////////////////////////////////////////////////////////////////////////////
  2860. //
  2861. //    HandleKeyEvent
  2862. //
  2863. //    This routine handles key events. The only ones we handle are menu shortcuts
  2864. //    and stopping the transfer shortcuts.
  2865. //
  2866. static void HandleKeyEvent (
  2867.     EventRecord            *pEventRecord)
  2868. {
  2869.     WindowPtr            pWin;
  2870.     WindowDataPtr        pWinData;
  2871.     char                key;
  2872.     
  2873.     key = pEventRecord->message & charCodeMask;
  2874.  
  2875.     if ((pEventRecord->modifiers & cmdKey) && (pEventRecord->what == keyDown))
  2876.     {
  2877.         if ((gSendingFile || gCheckingTransfer) && (key == kPeriodKey))
  2878.             StopTransfer(nil);
  2879.         else
  2880.             HandleMenuCommand(MenuKey(key));
  2881.     }
  2882.     
  2883.     if ((gSendingFile || gCheckingTransfer) && (key == kEscapeKey))
  2884.         StopTransfer(nil);
  2885.     
  2886.     if ((key == kPageUpKey) || (key == kPageDownKey) || (key == kHomeKey) || (key == kEndKey))
  2887.     {
  2888.         pWin = FrontWindow();
  2889.         if (pWin == gpFWXAppData->pSenderWindow)
  2890.         {
  2891.             pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2892.             HandleScrollAction(pWinData->hVScrollBar, key);
  2893.         }
  2894.     }
  2895. }
  2896.  
  2897. ////////////////////////////////////////////////////////////////////////////////
  2898. //
  2899. // HandleOSEvent
  2900. //
  2901. // This routine handles OS events.
  2902. //
  2903.  
  2904. static void HandleOSEvent(
  2905.     EventRecord            *pEventRecord)
  2906. {
  2907.     UInt32                osEventType;
  2908.  
  2909.     // Get the OS event type.
  2910.     osEventType = pEventRecord->message >> 24;
  2911.  
  2912.     switch (osEventType)
  2913.     {
  2914.         case suspendResumeMessage:
  2915.             if (pEventRecord->message & resumeFlag)
  2916.             {
  2917.                 gpFWXAppData->inForeground = true;
  2918.  
  2919.                 if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2920.                 {
  2921.                     NMRemove(gpFWXAppData->pNotifyRec);
  2922.                     gpFWXAppData->pNotifyRec->nmRefCon = kNoNotificationPosted;
  2923.                 }
  2924.             }
  2925.             else
  2926.                 gpFWXAppData->inForeground = false;
  2927.             
  2928.             HandleActivate(FrontWindow(), gpFWXAppData->inForeground);
  2929.             break;
  2930.     }
  2931. }
  2932.  
  2933.  
  2934. //////////////////////////////////////////////////////////////////////////////
  2935. //
  2936. //    HandleEvent
  2937. //
  2938. //    main event handling routine
  2939. //
  2940.  
  2941. static void HandleEvent (
  2942.     EventRecord        *theEvent)
  2943. {
  2944.     Point            point;
  2945.  
  2946.     switch (theEvent->what) {
  2947.         case mouseDown:
  2948.             HandleMouseDownEvent(theEvent);
  2949.             break;
  2950.  
  2951.         case updateEvt:
  2952.             HandleUpdateEvent(theEvent);
  2953.             break;
  2954.                     
  2955.         case keyDown:
  2956.         case autoKey:
  2957.             HandleKeyEvent(theEvent);
  2958.             break;
  2959.             
  2960.         case kHighLevelEvent:
  2961.             AEProcessAppleEvent(theEvent);
  2962.             break;
  2963.                     
  2964.         case osEvt:
  2965.             HandleOSEvent(theEvent);
  2966.             break;
  2967.             
  2968.         case diskEvt:
  2969.             if ((theEvent->message >> 16) != noErr) {
  2970.                 SetPt (&point, kDILeft, kDITop);
  2971.                 DIBadMount (point, theEvent->message);
  2972.             }
  2973.             break;
  2974.  
  2975.         case activateEvt:
  2976.             HandleActivate((WindowPtr) theEvent->message, (theEvent->modifiers & activeFlag) != 0);
  2977.             break;
  2978.     }
  2979. }
  2980.  
  2981. //////////////////////////////////////////////////////////////////////////////
  2982. //
  2983. //    HandleActivate
  2984. //
  2985. //    Take care of activating/deactivating, mainly just handling controls
  2986. //    and grow box.
  2987. //
  2988. static void HandleActivate(
  2989.     WindowPtr                pWin,
  2990.     Boolean                    becomingActive)
  2991. {
  2992.     WindowDataPtr            pWinData;
  2993.     
  2994.     if (IsAppWindow(pWin))
  2995.     {
  2996.         if (becomingActive)
  2997.         {
  2998.             gpFWXAppData->inForeground = true;
  2999.             if (pWin == gpFWXAppData->pSenderWindow)
  3000.             {
  3001.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3002.                 ShowControl(pWinData->hHScrollBar);
  3003.                 ShowControl(pWinData->hVScrollBar);
  3004.             }
  3005.             InvalRect(&pWin->portRect);
  3006.         }
  3007.         else
  3008.         {
  3009.             gpFWXAppData->inForeground = false;
  3010.             if (pWin == gpFWXAppData->pSenderWindow)
  3011.             {
  3012.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3013.                 HideControl(pWinData->hHScrollBar);
  3014.                 HideControl(pWinData->hVScrollBar);
  3015.                 DrawGrowIcon(pWin);
  3016.             }
  3017.         }
  3018.     }
  3019. }
  3020.  
  3021. //////////////////////////////////////////////////////////////////////////////
  3022. //
  3023. //    IsAppWindow
  3024. //
  3025. //    Check to see if our window needs handling for activate event.
  3026. //
  3027. static Boolean IsAppWindow(
  3028.     WindowPtr                pWin)
  3029. {
  3030.     SInt16                    windowKind;
  3031.  
  3032.     if (pWin == nil)
  3033.         return false;
  3034.     else {
  3035.         windowKind = ((WindowPeek) pWin)->windowKind;
  3036.         return (windowKind == userKind);
  3037.     }
  3038. }
  3039.  
  3040. //////////////////////////////////////////////////////////////////////////////
  3041. //
  3042. //    HandleIdle
  3043. //
  3044. //    At idle time check for processing send/receive information that may be
  3045. //    halted.
  3046. //
  3047. void HandleIdle(void)
  3048. {
  3049.     RecvNodePtr                pRecvNode;
  3050.     CurFileInfoPtr            pTxInfo;
  3051.     OSErr                    err;
  3052.     
  3053.     // received some data, handle it
  3054.     if (gReceiveQHdr.qHead != nil) {
  3055.         HandleReceive();
  3056.     }
  3057.     
  3058.     if (gSendingFile)
  3059.         UpdateProgressBar(FrontWindow(), kProgressBarUserItem);
  3060.     
  3061.     // if a file is being sent and end of file has been read, handle it
  3062.     if (gSendingDataFork || gSendingResFork)
  3063.     {
  3064.         if (gForkComplete && gForkWriteComplete)
  3065.         {
  3066.             HandleForkReadComplete();
  3067.         }
  3068.     }
  3069.  
  3070.     // if sending errors, show the alert and other routines
  3071.     // will take care of the clean up
  3072.     // JKL *** you sure about this?, no!
  3073.     if (gSendError != 0) {
  3074.         gSendError = (FWXNodeID) 0;
  3075.         err = GetNodeInfo(gSendError, &pRecvNode);
  3076.         if (err == noErr) {
  3077.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3078.             HandleCautionAlert(kCommunicationErrorAlertID);
  3079.         }
  3080.     }
  3081.     
  3082.     // if receiving error show the alert and also clean up
  3083.     // pending receive
  3084.     if (gReceiveError != 0) {
  3085.         gReceiveError = (FWXNodeID) 0;
  3086.         err = GetCurFileInfo(gReceiveError, &pTxInfo, false);
  3087.         if (err == noErr)
  3088.             HandleStopTransfer(pTxInfo);
  3089.         err = GetNodeInfo(gSendError, &pRecvNode);
  3090.         if (err == noErr) {
  3091.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3092.             HandleCautionAlert(kCommunicationErrorAlertID);
  3093.         }
  3094.     }
  3095. }
  3096.  
  3097. //////////////////////////////////////////////////////////////////////////////
  3098. //
  3099. //    HandleCautionAlert
  3100. //
  3101. //    Routine to call caution alerts
  3102. //
  3103. SInt16 HandleCautionAlert (
  3104.     SInt16                alertResID)
  3105. {
  3106.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3107.     SInt16                itemHit;
  3108.  
  3109.     itemHit = CautionAlert(alertResID, alertFilterProc);
  3110.     DisposeRoutineDescriptor(alertFilterProc);
  3111.     return itemHit;
  3112. }
  3113.  
  3114. //////////////////////////////////////////////////////////////////////////////
  3115. //
  3116. //    HandleStopAlert
  3117. //
  3118. //    Routine to call stop alerts
  3119. //
  3120. SInt16 HandleStopAlert (
  3121.     SInt16                alertResID)
  3122. {
  3123.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3124.     SInt16                itemHit;
  3125.  
  3126.     itemHit = StopAlert(alertResID, alertFilterProc);
  3127.     DisposeRoutineDescriptor(alertFilterProc);
  3128.     return itemHit;
  3129. }
  3130.  
  3131. //////////////////////////////////////////////////////////////////////////////
  3132. //
  3133. //    HandleNoteAlert
  3134. //
  3135. //    Routine to call note alerts
  3136. //
  3137. SInt16 HandleNoteAlert (
  3138.     SInt16                alertResID)
  3139. {
  3140.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3141.     SInt16                itemHit;
  3142.  
  3143.     itemHit = NoteAlert(alertResID, alertFilterProc);
  3144.     DisposeRoutineDescriptor(alertFilterProc);
  3145.     return itemHit;
  3146. }
  3147.  
  3148. //////////////////////////////////////////////////////////////////////////////
  3149. //
  3150. //    HandleAlert
  3151. //
  3152. //    Routine to call alerts
  3153. //
  3154. SInt16 HandleAlert (
  3155.     SInt16                alertResID)
  3156. {
  3157.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3158.     SInt16                itemHit;
  3159.  
  3160.     itemHit = Alert(alertResID, alertFilterProc);
  3161.     DisposeRoutineDescriptor(alertFilterProc);
  3162.     return itemHit;
  3163. }
  3164.  
  3165. //////////////////////////////////////////////////////////////////////////////
  3166. //
  3167. //    HandleAlertEventFilter
  3168. //
  3169. //    Handles alert filter events
  3170. //
  3171. static pascal Boolean HandleAlertEventFilter(
  3172.     DialogPtr            pDlog,
  3173.     EventRecord            *pEvent,
  3174.     SInt16                *itemHit)
  3175. {
  3176.     Handle                item;
  3177.     Rect                box;
  3178.     SInt32                finalTicks;
  3179.     SInt16                itemType;
  3180.     UInt8                key;
  3181.     Boolean                handledIt;
  3182.     
  3183.     handledIt = false;
  3184.     
  3185.     switch (pEvent->what)
  3186.     {
  3187.         case keyDown:
  3188.             key = pEvent->message & charCodeMask;
  3189.             
  3190.             if (key == kReturnKey || key == kEnterKey)
  3191.             {
  3192.                 GetDialogItem(pDlog, kOKButton, &itemType, &item, &box);
  3193.                 HiliteControl((ControlHandle) item, inButton);
  3194.                 Delay(8, &finalTicks);
  3195.                 HiliteControl((ControlHandle) item, 0);
  3196.                 handledIt = true;
  3197.                 *itemHit = kOKButton;
  3198.             }
  3199.             break;
  3200.         
  3201.         case nullEvent:
  3202.             HandleIdle();
  3203.             break;
  3204.         
  3205.         case updateEvt:
  3206.             HandleUpdateEvent(pEvent);
  3207.             break;
  3208.     }
  3209.     return handledIt;
  3210. }
  3211.  
  3212. //////////////////////////////////////////////////////////////////////////////
  3213. //
  3214. //    FWXMain
  3215. //
  3216. //    main routine for FWiX
  3217. //
  3218. #ifdef __MWERKS__
  3219. void main()
  3220. #else
  3221. void FWXMain()
  3222. #endif
  3223. {
  3224.     EventRecord        theEvent;
  3225.     OSErr            err = noErr;
  3226.     Boolean            gotEvent;
  3227.     
  3228.     err = FWXInit();
  3229.     
  3230.     if (err == noErr)
  3231.     {
  3232.         do
  3233.         {
  3234.             // Get any FWX events.
  3235.             GetNextFWXClientEvent (gpFWXAppData->fwxClientID);
  3236.             
  3237.             gotEvent = WaitNextEvent(everyEvent, &theEvent, 0, nil);
  3238.             
  3239.             if (gotEvent)
  3240.                 HandleEvent(&theEvent);
  3241.             else
  3242.                 HandleIdle();
  3243.             
  3244.         } while (!gpFWXAppData->quitFlag);
  3245.     }
  3246.     else if (err == memFullErr)
  3247.     {
  3248.         HandleStopAlert(kMemoryErrorAlertID);
  3249.     }
  3250.         
  3251.     FWXDispose ();
  3252. }
  3253.  
  3254. //////////////////////////////////////////////////////////////////////////////
  3255. //
  3256. //    SetupFWXNode
  3257. //
  3258. //    Register with the fam and get any currently connected nodes
  3259. //
  3260. static OSErr SetupFWXNode(void)
  3261. {
  3262.     UInt32                numFWXNodes;
  3263.     UInt32                nodeNum;
  3264.     FWXNodeID            *nodeIDList = nil;
  3265.     OSErr                err = noErr;
  3266.  
  3267.     err = RegisterFWXClientApplication(
  3268.                 &(gpFWXAppData->fwxClientID),
  3269.                 (UInt32) gpFWXAppData);
  3270.  
  3271.     // Get list of nodes.
  3272.     //zzz theoretically, new ones can be added while we're doing this.
  3273.     if (err == noErr) {
  3274.         err = GetFWXNodeList (nil, 0, &numFWXNodes);
  3275.     }
  3276.  
  3277.     if ((err == noErr) && (numFWXNodes > 0)) {
  3278.         nodeIDList = (FWXNodeID *) NewPtr(numFWXNodes * sizeof(FWXNodeID));
  3279.         if (nodeIDList != nil) {
  3280.             err = GetFWXNodeList(nodeIDList, numFWXNodes, &numFWXNodes);
  3281.         } else
  3282.             err = memFullErr;
  3283.     }
  3284.  
  3285.     if (err == noErr) {
  3286.         for (nodeNum = 0; nodeNum < numFWXNodes; nodeNum++) {
  3287.             SendDeviceAddedToSelf(nodeIDList[nodeNum]);
  3288.         }
  3289.     }
  3290.  
  3291.     if (nodeIDList != nil)
  3292.         DisposePtr((Ptr) nodeIDList);
  3293.             
  3294.     return err;
  3295. }
  3296.  
  3297.     
  3298. //////////////////////////////////////////////////////////////////////////////
  3299. //
  3300. //    SetupIOQueue
  3301. //
  3302. //    Setup the queueus. Initialize everything. Allocate buffers for reading
  3303. //    from files and writing to FireWire. The idea is to read then use the same
  3304. //    parameter block to write. The used queue is for taking a parameter block
  3305. //    and putting back on the free queue.
  3306. //
  3307. static OSErr SetupIOQueue(void)
  3308. {
  3309.     IOParamPtr                pIOPb;
  3310.     SInt16                    i;
  3311.     OSErr                    err = noErr;
  3312.     
  3313.     // init all of the queue headers
  3314.     gSendQHdr.qHead = nil;
  3315.     gSendQHdr.qTail = nil;
  3316.  
  3317.     gAESendQHdr.qHead = nil;
  3318.     gAESendQHdr.qTail = nil;
  3319.  
  3320.     gFileReadQHdr.qHead = nil;
  3321.     gFileReadQHdr.qTail = nil;
  3322.  
  3323.     gFWControlQHdr.qHead = nil;
  3324.     gFWControlQHdr.qTail = nil;
  3325.  
  3326.     gReceiveQHdr.qHead = nil;
  3327.     gReceiveQHdr.qTail = nil;
  3328.  
  3329.     gCurFileQHdr.qHead = nil;
  3330.     gCurFileQHdr.qTail = nil;
  3331.  
  3332.     queuesInitialized = true;
  3333.  
  3334.     // create file read parameter blocks and queue them on the file read queue
  3335.     for (i=0; i < kFileReadBufs; i++) {
  3336.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3337.         if (pIOPb != nil) {
  3338.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3339.         } else {
  3340.             FWDebugStr("\pOut of memory, SetupIOQ");
  3341.             err = memFullErr;
  3342.             break;
  3343.         }
  3344.                 
  3345.         // allocate data buffer on 4k boundary        
  3346.         pIOPb->ioBuffer = NewPtr(kFileReadBufSize + 4096);
  3347.         if (pIOPb->ioBuffer != nil) {
  3348.             HoldMemory (pIOPb->ioBuffer, kFileReadBufSize + 4096);
  3349.             pIOPb->ioBuffer = (Ptr) ((UInt32) pIOPb->ioBuffer + 4096);
  3350.             pIOPb->ioBuffer = (Ptr) ((UInt32) pIOPb->ioBuffer & 0xFFFFF000);
  3351.         } else {
  3352.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3353.             DisposePtr((Ptr) pIOPb);
  3354.             FWDebugStr("\pOut of memory, SetupIOQ");
  3355.             err = memFullErr;
  3356.             break;
  3357.         }
  3358.         
  3359.         Enqueue((QElemPtr) pIOPb, &gFileReadQHdr);
  3360.     }
  3361.     
  3362.     // create FW control parameter blocks and queue them on the FW control queue
  3363.     for (i=0; i < kFWControlParams; i++) {
  3364.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3365.         if (pIOPb != nil) {
  3366.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3367.         } else {
  3368.             FWDebugStr("\pOut of memory, SetupIOQ");
  3369.             err = memFullErr;
  3370.             break;
  3371.         }
  3372.                 
  3373.         pIOPb->ioBuffer = NewPtr(kFWControlParamBufferSize);
  3374.         if (pIOPb->ioBuffer != nil) {
  3375.             HoldMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3376.         } else {
  3377.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3378.             DisposePtr((Ptr) pIOPb);
  3379.             FWDebugStr("\pOut of memory, SetupIOQ");
  3380.             err = memFullErr;
  3381.             break;
  3382.         }
  3383.         
  3384.         Enqueue((QElemPtr) pIOPb, &gFWControlQHdr);
  3385.     }
  3386.     
  3387.     return err;    
  3388. }    
  3389.  
  3390. //////////////////////////////////////////////////////////////////////////////
  3391. //
  3392. //    InitNotification
  3393. //
  3394. //    Set up our notify routine
  3395. //zzz must deallocate pNotifyRec.
  3396. //
  3397. static OSErr InitNotification (void)
  3398. {
  3399.     NMRecPtr        pNotifyRec;
  3400.     OSErr            err = noErr;
  3401.  
  3402.     pNotifyRec = (NMRecPtr) NewPtrClear(sizeof(NMRec));
  3403.     if (pNotifyRec == nil)
  3404.         err = memFullErr;
  3405.     else {
  3406.         pNotifyRec->qType = nmType;
  3407.         pNotifyRec->nmResp = NewNMProc(HandleNotifyResponse);
  3408.         pNotifyRec->nmMark = 1;
  3409.         pNotifyRec->nmRefCon = kNoNotificationPosted;
  3410.         UpdateNotification(pNotifyRec);
  3411.     }
  3412.     gpFWXAppData->pNotifyRec = pNotifyRec;
  3413.     return err;
  3414. }
  3415.     
  3416. //////////////////////////////////////////////////////////////////////////////
  3417. //
  3418. //    UpdateNotification
  3419. //
  3420. //    Setup notification parameters according to prefs
  3421. //zzz must deallocate nmStr, hRes?
  3422. //
  3423. void UpdateNotification (
  3424.     NMRecPtr            pNMRec)
  3425. {
  3426.     Handle                hRes;
  3427.     SInt16                curAttributes;
  3428.     OSErr                err;
  3429.     SInt8                notifyPrefs = gpFWXAppData->fwixPrefs;
  3430.     
  3431.     if (notifyPrefs & kNotifyFlash)
  3432.     {
  3433.         if (pNMRec->nmIcon == nil)
  3434.         {
  3435.             // get an icon to flash
  3436.             err = GetIconSuite(&hRes, kAppIconSuiteID, svAllSmallData);
  3437.             if ((err == noErr) && (hRes != nil))
  3438.             {
  3439.                 curAttributes = GetResAttrs(hRes);
  3440.                 if (curAttributes & resPurgeable)
  3441.                     HNoPurge(hRes);
  3442.                 pNMRec->nmIcon = hRes;
  3443.             }
  3444.             else
  3445.                 pNMRec->nmIcon = nil;
  3446.         }
  3447.     }
  3448.     else if (pNMRec->nmIcon != nil)
  3449.     {
  3450.         DisposeIconSuite(pNMRec->nmIcon, false);
  3451.         pNMRec->nmIcon = nil;
  3452.     }
  3453.     
  3454. /*
  3455.     *** JKl - do the dialog ourselves so we can continue processing in the background,
  3456.     *** this code uses notification manager for dialog.
  3457.     *** Need to post dialog needed message and display dialog if we are in background.
  3458.     *** HandleReceive displays the dialog once receive is complete.
  3459.     if (notifyPrefs & kNotifyAlert)
  3460.     {
  3461.         if (pNMRec->nmStr == nil)
  3462.         {
  3463.             // get an alert string
  3464.             hRes = GetResource('STR ', kNotifyString);
  3465.             pNMRec->nmStr = (StringPtr) NewPtr(**hRes + 1);
  3466.             if (pNMRec->nmStr != nil)
  3467.                 BlockMove(*hRes, pNMRec->nmStr, **hRes + 1);
  3468.             ReleaseResource(hRes);
  3469.         }
  3470.     }
  3471.     else if (pNMRec->nmStr != nil)
  3472.     {
  3473.         DisposePtr((Ptr) pNMRec->nmStr);
  3474.         pNMRec->nmStr = nil;
  3475.     }
  3476. */
  3477. /*
  3478.     *** JKL - just play the sound our selves, this code uses the notification manager to make the sound
  3479.     *** HandleReceive now plays the sound once receive is complete    
  3480.     if (notifyPrefs & kNotifySound)
  3481.     {
  3482.         if (pNMRec->nmSound == nil)
  3483.         {
  3484.             // get the sound to play
  3485.             hRes = GetNamedResource('snd ', gpFWXAppData->fwixNotifySound);
  3486.             if (hRes != nil)
  3487.             {
  3488.                 curAttributes = GetResAttrs(hRes);
  3489.                 if (curAttributes & resPurgeable)
  3490.                     HNoPurge(hRes);
  3491.                 pNMRec->nmSound = hRes;
  3492.             }
  3493.             else
  3494.                 pNMRec->nmSound = (Handle) -1;        // at least play the system alert
  3495.         }
  3496.     } else if (pNMRec->nmSound != nil) {
  3497.         ReleaseResource(pNMRec->nmSound);
  3498.         pNMRec->nmSound = nil;
  3499.     }
  3500. */
  3501. }
  3502.     
  3503. //////////////////////////////////////////////////////////////////////////////
  3504. //
  3505. //    HandleNotifyResponse
  3506. //
  3507. //    Handle notification manager response
  3508. //
  3509. pascal void HandleNotifyResponse (
  3510.     NMRecPtr            pNMRequest)
  3511. {
  3512.     if (gpFWXAppData->inForeground) {
  3513.         NMRemove(pNMRequest);
  3514.         pNMRequest->nmRefCon = kNoNotificationPosted;
  3515.     }
  3516. }
  3517.  
  3518. //////////////////////////////////////////////////////////////////////////////
  3519. //
  3520. //    FWXInit
  3521. //
  3522. //    Initialization routine for FWX
  3523. //
  3524. static OSErr FWXInit(void)
  3525. {
  3526.     Handle            hString;
  3527.     SInt16            curResFile;
  3528.     SInt16            itemHit;
  3529.     OSErr            err = noErr;
  3530.     
  3531.     // Create global data record
  3532.     gpFWXAppData = (FWXAppDataPtr)
  3533.         NewPtrClear(sizeof (FWXAppData));
  3534.     if (gpFWXAppData == nil)
  3535.         err = memFullErr;
  3536.  
  3537.     if (err == noErr) {
  3538.         gpFWXAppData->quitFlag = false;
  3539.         gpFWXAppData->inForeground = true;
  3540.         gpFWXAppData->fwxClientID = kInvalidFWXClientID;
  3541.         gpFWXAppData->pSenderWindow = nil;
  3542.         
  3543.         gCheckingTransfer = false;
  3544.         gSendingFile = false;
  3545.         gSendingDataFork = false;
  3546.         gSendingResFork = false;
  3547.         gForkComplete = true;
  3548.         gForkWriteComplete = true;
  3549.         gSendError = (FWXNodeID) 0;
  3550.         gReceiveError = (FWXNodeID) 0;
  3551.         
  3552.         InitGraf(&qd.thePort);
  3553.         InitFonts();
  3554.         InitWindows();
  3555.         InitMenus();
  3556.         TEInit();
  3557.         InitDialogs(nil);
  3558.         InitCursor();
  3559.             
  3560.         // Make sure there is a sharing setup macintosh name
  3561.         curResFile = CurResFile();
  3562.         UseResFile(kSystemResFile);
  3563.         hString = Get1Resource('STR ', kNetworkNameID);
  3564.         UseResFile(curResFile);
  3565.         if ((hString == nil) || (**hString == 0))
  3566.         {
  3567.             // no name or string is empty
  3568.             itemHit = HandleStopAlert(kNoNameAlertID);
  3569.             if (itemHit == kOKButton)
  3570.                 OpenSharingSetup();
  3571.             ExitToShell();
  3572.         }
  3573.  
  3574.         if (err == noErr)
  3575.             err = SetupIOQueue();
  3576.         if (err == noErr)
  3577.             err = InstallAppleEventHandlers();
  3578.         if (err == noErr)
  3579.             err = InstallCompletionRoutineProcs();
  3580.         if (err == noErr)
  3581.             err = InitPrefs();
  3582.         if (err == noErr)
  3583.             err = CreateMenus();
  3584.         if (err == noErr)
  3585.             err = CreateWindow();
  3586.         if (err == noErr)
  3587.             err = InstallDragHandlers();
  3588.         if (err == noErr)
  3589.             err = SetupFWXNode();
  3590.         if (err == noErr)
  3591.             err = InitNotification();
  3592.     }
  3593.     return err;
  3594. }            
  3595.     
  3596. //////////////////////////////////////////////////////////////////////////////
  3597. //
  3598. //    FWXDispose
  3599. //
  3600. //    Disposal routine for FWX
  3601. //
  3602. static OSErr FWXDispose(void)
  3603. {
  3604.     IOParamPtr        pIOPb;
  3605.     OSErr            err = noErr;
  3606.  
  3607.     // dispose of file write parameter blocks and write queue
  3608.     //zzz must ensure that none are still pending
  3609.  
  3610.     // dispose of FW control parameter blocks and write queue
  3611.     //zzz must ensure that none are still pending
  3612.     if (queuesInitialized) {
  3613.         pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3614.         while (pIOPb) {
  3615.             Dequeue ((QElemPtr) pIOPb, &gFWControlQHdr);
  3616.             UnholdMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3617.             DisposePtr (pIOPb->ioBuffer);
  3618.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3619.             DisposePtr ((Ptr) pIOPb);
  3620.  
  3621.             pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3622.         }
  3623.     }
  3624.  
  3625.     // dispose of file read parameter blocks and write queue
  3626.     //zzz must ensure that none are still pending
  3627.     if (queuesInitialized) {
  3628.         pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3629.         while (pIOPb) {
  3630.             Dequeue ((QElemPtr) pIOPb, &gFileReadQHdr);
  3631.             UnholdMemory (pIOPb->ioBuffer, kFileReadBufSize);
  3632.             DisposePtr (pIOPb->ioBuffer);
  3633.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3634.             DisposePtr ((Ptr) pIOPb);
  3635.  
  3636.             pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3637.         }
  3638.     }
  3639.  
  3640.     if (gpFWXAppData != nil) {
  3641.         // Unregister as a client of FWiX.
  3642.         if (gpFWXAppData->fwxClientID != (FWXNodeID) kInvalidFWXClientID)
  3643.             UnregisterFWXClientApplication (gpFWXAppData->fwxClientID);
  3644.  
  3645.         // Deallocate our globals.
  3646.         DisposePtr ((Ptr) gpFWXAppData);
  3647.         gpFWXAppData = nil;
  3648.     }
  3649.  
  3650.     return err;    
  3651. }
  3652.